home *** CD-ROM | disk | FTP | other *** search
/ Amiga Games Extra 1996 September / Amiga Games Extra CD-ROM 9-1996.iso / userbox / publicdomain / vim-4.2 / src / screen.c < prev    next >
C/C++ Source or Header  |  1996-06-17  |  80KB  |  3,363 lines

  1. /* vi:set ts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8.  
  9. /*
  10.  * screen.c: code for displaying on the screen
  11.  */
  12.  
  13. #include "vim.h"
  14. #include "globals.h"
  15. #include "proto.h"
  16. #include "option.h"
  17. #include "ops.h"        /* For op_inclusive */
  18.  
  19. char *tgoto __PARMS((char *cm, int col, int line));
  20.  
  21. static int        canopt;            /* TRUE when cursor goto can be optimized */
  22. static int        attributes = 0;    /* current attributes for screen character*/
  23. static int         highlight_attr = 0;    /* attributes when highlighting on */
  24. #ifdef RIGHTLEFT
  25. static int        rightleft = 0;    /* set to 1 for right to left in screen_fill */
  26. #endif
  27.  
  28. static int win_line __ARGS((WIN *, linenr_t, int, int));
  29. static void comp_Botline_sub __ARGS((WIN *wp, linenr_t lnum, int done));
  30. static void screen_char __ARGS((char_u *, int, int));
  31. static void screenclear2 __ARGS((void));
  32. static void lineclear __ARGS((char_u *p));
  33. static int screen_ins_lines __ARGS((int, int, int, int));
  34.  
  35. /*
  36.  * updateline() - like updateScreen() but only for cursor line
  37.  *
  38.  * Check if the size of the cursor line has changed.  If it did change, lines
  39.  * below the cursor will move up or down and we need to call the routine
  40.  * updateScreen() to examine the entire screen.
  41.  */
  42.     void
  43. updateline()
  44. {
  45.     int         row;
  46.     int         n;
  47.  
  48.     if (!screen_valid(TRUE))
  49.         return;
  50.  
  51.     if (must_redraw)                    /* must redraw whole screen */
  52.     {
  53.         updateScreen(must_redraw);
  54.         return;
  55.     }
  56.  
  57.     if (RedrawingDisabled)
  58.     {
  59.         must_redraw = NOT_VALID;        /* remember to update later */
  60.         return;
  61.     }
  62.  
  63.     cursor_off();
  64.  
  65.     (void)set_highlight('v');
  66.     row = win_line(curwin, curwin->w_cursor.lnum,
  67.                                        curwin->w_cline_row, curwin->w_height);
  68.  
  69.     if (row == curwin->w_height + 1)    /* line too long for window */
  70.     {
  71.             /* window needs to be scrolled up to show the cursor line */
  72.         if (curwin->w_topline < curwin->w_cursor.lnum)
  73.             ++curwin->w_topline;
  74.         updateScreen(VALID_TO_CURSCHAR);
  75.         cursupdate();
  76.     }
  77.     else if (!dollar_vcol)
  78.     {
  79.         n = row - curwin->w_cline_row;
  80.         if (n != curwin->w_cline_height)        /* line changed size */
  81.         {
  82.             if (n < curwin->w_cline_height)     /* got smaller: delete lines */
  83.                 win_del_lines(curwin, row,
  84.                                      curwin->w_cline_height - n, FALSE, TRUE);
  85.             else                                /* got bigger: insert lines */
  86.                 win_ins_lines(curwin,
  87.                                  curwin->w_cline_row + curwin->w_cline_height,
  88.                                      n - curwin->w_cline_height, FALSE, TRUE);
  89.             updateScreen(VALID_TO_CURSCHAR);
  90.         }
  91.         else if (clear_cmdline || redraw_cmdline)
  92.             showmode();                /* clear cmdline, show mode and ruler */
  93.     }
  94. }
  95.  
  96. /*
  97.  * update all windows that are editing the current buffer
  98.  */
  99.     void
  100. update_curbuf(type)
  101.     int            type;
  102. {
  103.     WIN                *wp;
  104.  
  105.     for (wp = firstwin; wp; wp = wp->w_next)
  106.         if (wp->w_buffer == curbuf && wp->w_redr_type < type)
  107.             wp->w_redr_type = type;
  108.     updateScreen(type);
  109. }
  110.  
  111. /*
  112.  * updateScreen()
  113.  *
  114.  * Based on the current value of curwin->w_topline, transfer a screenfull
  115.  * of stuff from Filemem to NextScreen, and update curwin->w_botline.
  116.  */
  117.  
  118.     void
  119. updateScreen(type)
  120.     int             type;
  121. {
  122.     WIN                *wp;
  123.  
  124.     if (!screen_valid(TRUE))
  125.         return;
  126.  
  127.     dollar_vcol = 0;
  128.  
  129.     if (must_redraw)
  130.     {
  131.         if (type < must_redraw)        /* use maximal type */
  132.             type = must_redraw;
  133.         must_redraw = 0;
  134.     }
  135.  
  136.     if (type == CURSUPD)        /* update cursor and then redraw NOT_VALID */
  137.     {
  138.         curwin->w_lsize_valid = 0;
  139.         cursupdate();            /* will call updateScreen() */
  140.         return;
  141.     }
  142.     if (curwin->w_lsize_valid == 0 && type < NOT_VALID)
  143.         type = NOT_VALID;
  144.  
  145.      if (RedrawingDisabled)
  146.     {
  147.         must_redraw = type;        /* remember type for next time */
  148.         curwin->w_redr_type = type;
  149.         curwin->w_lsize_valid = 0;        /* don't use w_lsize[] now */
  150.         return;
  151.     }
  152.  
  153.     /*
  154.      * if the screen was scrolled up when displaying a message, scroll it down
  155.      */
  156.     if (msg_scrolled)
  157.     {
  158.         clear_cmdline = TRUE;
  159.         if (msg_scrolled > Rows - 5)        /* clearing is faster */
  160.             type = CLEAR;
  161.         else if (type != CLEAR)
  162.         {
  163.             if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows) == FAIL)
  164.                 type = CLEAR;
  165.             win_rest_invalid(firstwin);        /* should do only first/last few */
  166.         }
  167.         msg_scrolled = 0;
  168.         need_wait_return = FALSE;
  169.     }
  170.  
  171.     /*
  172.      * reset cmdline_row now (may have been changed temporarily)
  173.      */
  174.     compute_cmdrow();
  175.  
  176.     if (type == CLEAR)            /* first clear screen */
  177.     {
  178.         screenclear();            /* will reset clear_cmdline */
  179.         type = NOT_VALID;
  180.     }
  181.  
  182.     if (clear_cmdline)            /* first clear cmdline */
  183.     {
  184.         if (emsg_on_display)
  185.         {
  186.             mch_delay(1000L, TRUE);
  187.             emsg_on_display = FALSE;
  188.         }
  189.         msg_row = cmdline_row;
  190.         msg_col = 0;
  191.         msg_clr_eos();            /* will reset clear_cmdline */
  192.     }
  193.  
  194. /* return if there is nothing to do */
  195.     if (!((type == VALID && curwin->w_topline == curwin->w_lsize_lnum[0]) ||
  196.             (type == INVERTED &&
  197.                     curwin->w_old_cursor_lnum == curwin->w_cursor.lnum &&
  198.                     curwin->w_old_cursor_vcol == curwin->w_virtcol &&
  199.                     curwin->w_old_curswant == curwin->w_curswant)))
  200.     {
  201.         /*
  202.          * go from top to bottom through the windows, redrawing the ones that
  203.          * need it
  204.          */
  205.         curwin->w_redr_type = type;
  206.         cursor_off();
  207.         for (wp = firstwin; wp; wp = wp->w_next)
  208.         {
  209.             if (wp->w_redr_type)
  210.                 win_update(wp);
  211.             if (wp->w_redr_status)
  212.                 win_redr_status(wp);
  213.         }
  214.     }
  215.     if (redraw_cmdline)
  216.         showmode();
  217. }
  218.  
  219. #ifdef USE_GUI
  220. /*
  221.  * Update a single window, its status line and maybe the command line msg.
  222.  * Used for the GUI scrollbar.
  223.  */
  224.     void
  225. updateWindow(wp)
  226.     WIN        *wp;
  227. {
  228.     win_update(wp);
  229.     if (wp->w_redr_status)
  230.         win_redr_status(wp);
  231.     if (redraw_cmdline)
  232.         showmode();
  233. }
  234. #endif
  235.  
  236. /*
  237.  * update a single window
  238.  *
  239.  * This may cause the windows below it also to be redrawn
  240.  */
  241.     void
  242. win_update(wp)
  243.     WIN        *wp;
  244. {
  245.     int                type = wp->w_redr_type;
  246.     register int    row;
  247.     register int    endrow;
  248.     linenr_t        lnum;
  249.     linenr_t        lastline = 0;    /* only valid if endrow != Rows -1 */
  250.     int                done;            /* if TRUE, we hit the end of the file */
  251.     int                didline;        /* if TRUE, we finished the last line */
  252.     int             srow = 0;        /* starting row of the current line */
  253.     int             idx;
  254.     int             i;
  255.     long             j;
  256.  
  257.     if (type == NOT_VALID)
  258.     {
  259.         wp->w_redr_status = TRUE;
  260.         wp->w_lsize_valid = 0;
  261.     }
  262.  
  263.     idx = 0;
  264.     row = 0;
  265.     lnum = wp->w_topline;
  266.  
  267.     /* The number of rows shown is w_height. */
  268.     /* The default last row is the status/command line. */
  269.     endrow = wp->w_height;
  270.  
  271.     if (type == VALID || type == VALID_TO_CURSCHAR)
  272.     {
  273.         /*
  274.          * We handle two special cases:
  275.          * 1: we are off the top of the screen by a few lines: scroll down
  276.          * 2: wp->w_topline is below wp->w_lsize_lnum[0]: may scroll up
  277.          */
  278.         if (wp->w_topline < wp->w_lsize_lnum[0])    /* may scroll down */
  279.         {
  280.             j = wp->w_lsize_lnum[0] - wp->w_topline;
  281.             if (j < wp->w_height - 2)                /* not too far off */
  282.             {
  283.                 lastline = wp->w_lsize_lnum[0] - 1;
  284.                 i = plines_m_win(wp, wp->w_topline, lastline);
  285.                 if (i < wp->w_height - 2)        /* less than a screen off */
  286.                 {
  287.                     /*
  288.                      * Try to insert the correct number of lines.
  289.                      * If not the last window, delete the lines at the bottom.
  290.                      * win_ins_lines may fail.
  291.                      */
  292.                     if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK &&
  293.                                                     wp->w_lsize_valid)
  294.                     {
  295.                         endrow = i;
  296.  
  297.                         if ((wp->w_lsize_valid += j) > wp->w_height)
  298.                             wp->w_lsize_valid = wp->w_height;
  299.                         for (idx = wp->w_lsize_valid; idx - j >= 0; idx--)
  300.                         {
  301.                             wp->w_lsize_lnum[idx] = wp->w_lsize_lnum[idx - j];
  302.                             wp->w_lsize[idx] = wp->w_lsize[idx - j];
  303.                         }
  304.                         idx = 0;
  305.                     }
  306.                 }
  307.                 else if (lastwin == firstwin)
  308.                     screenclear();    /* far off: clearing the screen is faster */
  309.             }
  310.             else if (lastwin == firstwin)
  311.                 screenclear();        /* far off: clearing the screen is faster */
  312.         }
  313.         else                            /* may scroll up */
  314.         {
  315.             j = -1;
  316.                         /* try to find wp->w_topline in wp->w_lsize_lnum[] */
  317.             for (i = 0; i < wp->w_lsize_valid; i++)
  318.             {
  319.                 if (wp->w_lsize_lnum[i] == wp->w_topline)
  320.                 {
  321.                     j = i;
  322.                     break;
  323.                 }
  324.                 row += wp->w_lsize[i];
  325.             }
  326.             if (j == -1)    /* wp->w_topline is not in wp->w_lsize_lnum */
  327.             {
  328.                 row = 0;
  329.                 if (lastwin == firstwin)
  330.                     screenclear();    /* far off: clearing the screen is faster */
  331.             }
  332.             else
  333.             {
  334.                 /*
  335.                  * Try to delete the correct number of lines.
  336.                  * wp->w_topline is at wp->w_lsize_lnum[i].
  337.                  */
  338.                 if ((row == 0 || win_del_lines(wp, 0, row,
  339.                             FALSE, wp == firstwin) == OK) && wp->w_lsize_valid)
  340.                 {
  341.                     srow = row;
  342.                     row = 0;
  343.                     for (;;)
  344.                     {
  345.                         if (type == VALID_TO_CURSCHAR &&
  346.                                                     lnum == wp->w_cursor.lnum)
  347.                                 break;
  348.                         if (row + srow + (int)wp->w_lsize[j] >= wp->w_height)
  349.                                 break;
  350.                         wp->w_lsize[idx] = wp->w_lsize[j];
  351.                         wp->w_lsize_lnum[idx] = lnum++;
  352.  
  353.                         row += wp->w_lsize[idx++];
  354.                         if ((int)++j >= wp->w_lsize_valid)
  355.                             break;
  356.                     }
  357.                     wp->w_lsize_valid = idx;
  358.                 }
  359.                 else
  360.                     row = 0;        /* update all lines */
  361.             }
  362.         }
  363.         if (endrow == wp->w_height && idx == 0)     /* no scrolling */
  364.                 wp->w_lsize_valid = 0;
  365.     }
  366.  
  367.     done = didline = FALSE;
  368.  
  369.     if (VIsual_active)        /* check if we are updating the inverted part */
  370.     {
  371.         linenr_t    from, to;
  372.  
  373.     /* find the line numbers that need to be updated */
  374.         if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum)
  375.         {
  376.             from = curwin->w_cursor.lnum;
  377.             to = wp->w_old_cursor_lnum;
  378.         }
  379.         else
  380.         {
  381.             from = wp->w_old_cursor_lnum;
  382.             to = curwin->w_cursor.lnum;
  383.         }
  384.             /* if VIsual changed, update the maximal area */
  385.         if (VIsual.lnum != wp->w_old_visual_lnum)
  386.         {
  387.             if (wp->w_old_visual_lnum < from)
  388.                 from = wp->w_old_visual_lnum;
  389.             if (wp->w_old_visual_lnum > to)
  390.                 to = wp->w_old_visual_lnum;
  391.             if (VIsual.lnum < from)
  392.                 from = VIsual.lnum;
  393.             if (VIsual.lnum > to)
  394.                 to = VIsual.lnum;
  395.         }
  396.     /* if in block mode and changed column or wp->w_curswant: update all
  397.      * lines */
  398.         if (VIsual_mode == Ctrl('V') &&
  399.                         (curwin->w_virtcol != wp->w_old_cursor_vcol ||
  400.                         wp->w_curswant != wp->w_old_curswant))
  401.         {
  402.             if (from > VIsual.lnum)
  403.                 from = VIsual.lnum;
  404.             if (to < VIsual.lnum)
  405.                 to = VIsual.lnum;
  406.         }
  407.  
  408.         if (from < wp->w_topline)
  409.             from = wp->w_topline;
  410.         if (from >= wp->w_botline)
  411.             from = wp->w_botline - 1;
  412.         if (to >= wp->w_botline)
  413.             to = wp->w_botline - 1;
  414.  
  415.     /* find the minimal part to be updated */
  416.         if (type == INVERTED)
  417.         {
  418.             while (lnum < from)                        /* find start */
  419.             {
  420.                 row += wp->w_lsize[idx++];
  421.                 ++lnum;
  422.             }
  423.             srow = row;
  424.             for (j = idx; j < wp->w_lsize_valid; ++j)    /* find end */
  425.             {
  426.                 if (wp->w_lsize_lnum[j] == to + 1)
  427.                 {
  428.                     endrow = srow;
  429.                     break;
  430.                 }
  431.                 srow += wp->w_lsize[j];
  432.             }
  433.         }
  434.  
  435.     /* if we update the lines between from and to set old_cursor */
  436.         if (type == INVERTED || (lnum <= from &&
  437.                                   (endrow == wp->w_height || lastline >= to)))
  438.         {
  439.             wp->w_old_cursor_lnum = curwin->w_cursor.lnum;
  440.             wp->w_old_cursor_vcol = curwin->w_virtcol;
  441.             wp->w_old_visual_lnum = VIsual.lnum;
  442.             wp->w_old_curswant = wp->w_curswant;
  443.         }
  444.     }
  445.     else
  446.     {
  447.         wp->w_old_cursor_lnum = 0;
  448.         wp->w_old_visual_lnum = 0;
  449.     }
  450.  
  451.     (void)set_highlight('v');
  452.  
  453.     /*
  454.      * Update the screen rows from "row" to "endrow".
  455.      * Start at line "lnum" which is at wp->w_lsize_lnum[idx].
  456.      */
  457.     for (;;)
  458.     {
  459.         if (lnum > wp->w_buffer->b_ml.ml_line_count)
  460.         {
  461.             done = TRUE;        /* hit the end of the file */
  462.             break;
  463.         }
  464.         srow = row;
  465.         row = win_line(wp, lnum, srow, endrow);
  466.         if (row > endrow)        /* past end of screen */
  467.         {                        /* we may need the size of that */
  468.             wp->w_lsize[idx] = plines_win(wp, lnum);
  469.             wp->w_lsize_lnum[idx++] = lnum;        /* too long line later on */
  470.             break;
  471.         }
  472.  
  473.         wp->w_lsize[idx] = row - srow;
  474.         wp->w_lsize_lnum[idx++] = lnum;
  475.         if (++lnum > wp->w_buffer->b_ml.ml_line_count)
  476.         {
  477.             done = TRUE;
  478.             break;
  479.         }
  480.  
  481.         if (row == endrow)
  482.         {
  483.             didline = TRUE;
  484.             break;
  485.         }
  486.     }
  487.     if (idx > wp->w_lsize_valid)
  488.         wp->w_lsize_valid = idx;
  489.  
  490.     /* Do we have to do off the top of the screen processing ? */
  491.     if (endrow != wp->w_height)
  492.     {
  493.         row = 0;
  494.         for (idx = 0; idx < wp->w_lsize_valid && row < wp->w_height; idx++)
  495.             row += wp->w_lsize[idx];
  496.  
  497.         if (row < wp->w_height)
  498.         {
  499.             done = TRUE;
  500.         }
  501.         else if (row > wp->w_height)    /* Need to blank out the last line */
  502.         {
  503.             lnum = wp->w_lsize_lnum[idx - 1];
  504.             srow = row - wp->w_lsize[idx - 1];
  505.             didline = FALSE;
  506.         }
  507.         else
  508.         {
  509.             lnum = wp->w_lsize_lnum[idx - 1] + 1;
  510.             didline = TRUE;
  511.         }
  512.     }
  513.  
  514.     wp->w_empty_rows = 0;
  515.     /*
  516.      * If we didn't hit the end of the file, and we didn't finish the last
  517.      * line we were working on, then the line didn't fit.
  518.      */
  519.     if (!done && !didline)
  520.     {
  521.         if (lnum == wp->w_topline)
  522.         {
  523.             /*
  524.              * Single line that does not fit!
  525.              * Fill last line with '@' characters.
  526.              */
  527.             screen_fill(wp->w_winpos + wp->w_height - 1,
  528.                     wp->w_winpos + wp->w_height, 0, (int)Columns, '@', '@');
  529.             wp->w_botline = lnum + 1;
  530.         }
  531.         else
  532.         {
  533.             /*
  534.              * Clear the rest of the screen and mark the unused lines.
  535.              */
  536. #ifdef RIGHTLEFT
  537.             if (wp->w_p_rl)
  538.                 rightleft = 1;
  539. #endif
  540.             screen_fill(wp->w_winpos + srow,
  541.                     wp->w_winpos + wp->w_height, 0, (int)Columns, '@', ' ');
  542. #ifdef RIGHTLEFT
  543.             rightleft = 0;
  544. #endif
  545.             wp->w_botline = lnum;
  546.             wp->w_empty_rows = wp->w_height - srow;
  547.         }
  548.     }
  549.     else
  550.     {
  551.         /* make sure the rest of the screen is blank */
  552.         /* put '~'s on rows that aren't part of the file. */
  553. #ifdef RIGHTLEFT
  554.         if (wp->w_p_rl)
  555.             rightleft = 1;
  556. #endif
  557.         screen_fill(wp->w_winpos + row,
  558.                     wp->w_winpos + wp->w_height, 0, (int)Columns, '~', ' ');
  559. #ifdef RIGHTLEFT
  560.         rightleft = 0;
  561. #endif
  562.         wp->w_empty_rows = wp->w_height - row;
  563.  
  564.         if (done)                /* we hit the end of the file */
  565.             wp->w_botline = wp->w_buffer->b_ml.ml_line_count + 1;
  566.         else
  567.             wp->w_botline = lnum;
  568.     }
  569.  
  570.     wp->w_redr_type = 0;
  571. }
  572.  
  573. /*
  574.  * mark all status lines for redraw; used after first :cd
  575.  */
  576.     void
  577. status_redraw_all()
  578. {
  579.     WIN        *wp;
  580.  
  581.     for (wp = firstwin; wp; wp = wp->w_next)
  582.         wp->w_redr_status = TRUE;
  583.     updateScreen(NOT_VALID);
  584. }
  585.  
  586. /*
  587.  * Redraw the status line of window wp.
  588.  *
  589.  * If inversion is possible we use it. Else '=' characters are used.
  590.  */
  591.     void
  592. win_redr_status(wp)
  593.     WIN        *wp;
  594. {
  595.     int        row;
  596.     char_u    *p;
  597.     int        len;
  598.     int        fillchar;
  599.  
  600.     if (wp->w_status_height)                    /* if there is a status line */
  601.     {
  602.         if (set_highlight('s') == OK)            /* can highlight */
  603.         {
  604.             fillchar = ' ';
  605.             start_highlight();
  606.         }
  607.         else                                    /* can't highlight, use '=' */
  608.             fillchar = '=';
  609.  
  610.         p = wp->w_buffer->b_xfilename;
  611.         if (p == NULL)
  612.             STRCPY(NameBuff, "[No File]");
  613.         else
  614.         {
  615.             home_replace(wp->w_buffer, p, NameBuff, MAXPATHL);
  616.             trans_characters(NameBuff, MAXPATHL);
  617.         }
  618.         p = NameBuff;
  619.         len = STRLEN(p);
  620.  
  621.         if (wp->w_buffer->b_help || wp->w_buffer->b_changed ||
  622.                                                          wp->w_buffer->b_p_ro)
  623.             *(p + len++) = ' ';
  624.         if (wp->w_buffer->b_help)
  625.         {
  626.             STRCPY(p + len, "[help]");
  627.             len += 6;
  628.         }
  629.         if (wp->w_buffer->b_changed)
  630.         {
  631.             STRCPY(p + len, "[+]");
  632.             len += 3;
  633.         }
  634.         if (wp->w_buffer->b_p_ro)
  635.         {
  636.             STRCPY(p + len, "[RO]");
  637.             len += 4;
  638.         }
  639.  
  640.         if (len > ru_col - 1)
  641.         {
  642.             p += len - (ru_col - 1);
  643.             *p = '<';
  644.             len = ru_col - 1;
  645.         }
  646.  
  647.         row = wp->w_winpos + wp->w_height;
  648.         screen_msg(p, row, 0);
  649.         screen_fill(row, row + 1, len, ru_col, fillchar, fillchar);
  650.  
  651.         stop_highlight();
  652.         win_redr_ruler(wp, TRUE);
  653.     }
  654.     else    /* no status line, can only be last window */
  655.         redraw_cmdline = TRUE;
  656.     wp->w_redr_status = FALSE;
  657. }
  658.  
  659. /*
  660.  * display line "lnum" of window 'wp' on the screen
  661.  * Start at row "startrow", stop when "endrow" is reached.
  662.  * Return the number of last row the line occupies.
  663.  */
  664.  
  665.     static int
  666. win_line(wp, lnum, startrow, endrow)
  667.     WIN                *wp;
  668.     linenr_t        lnum;
  669.     int             startrow;
  670.     int             endrow;
  671. {
  672.     char_u             *screenp;
  673.     int                c;
  674.     int                col;                /* visual column on screen */
  675.     long            vcol;                /* visual column for tabs */
  676.     int                row;                /* row in the window, excl w_winpos */
  677.     int                screen_row;            /* row on the screen, incl w_winpos */
  678.     char_u            *ptr;
  679.     char_u            extra[16];            /* "%ld" must fit in here */
  680.     char_u            *p_extra;
  681.     char_u            *showbreak = NULL;
  682.     int             n_extra;
  683.     int                n_spaces = 0;
  684.  
  685.     int                fromcol, tocol;        /* start/end of inverting */
  686.     int                noinvcur = FALSE;    /* don't invert the cursor */
  687.     FPOS            *top, *bot;
  688.  
  689.     if (startrow > endrow)                /* past the end already! */
  690.         return startrow;
  691.  
  692.     row = startrow;
  693.     screen_row = row + wp->w_winpos;
  694.     col = 0;
  695.     vcol = 0;
  696.     fromcol = -10;
  697.     tocol = MAXCOL;
  698.     canopt = TRUE;
  699.  
  700.     /*
  701.      * handle visual active in this window
  702.      */
  703.     if (VIsual_active && wp->w_buffer == curwin->w_buffer)
  704.     {
  705.                                         /* Visual is after curwin->w_cursor */
  706.         if (ltoreq(curwin->w_cursor, VIsual))
  707.         {
  708.             top = &curwin->w_cursor;
  709.             bot = &VIsual;
  710.         }
  711.         else                            /* Visual is before curwin->w_cursor */
  712.         {
  713.             top = &VIsual;
  714.             bot = &curwin->w_cursor;
  715.         }
  716.         if (VIsual_mode == Ctrl('V'))    /* block mode */
  717.         {
  718.             if (lnum >= top->lnum && lnum <= bot->lnum)
  719.             {
  720.                 colnr_t        from, to;
  721.  
  722.                 getvcol(wp, top, (colnr_t *)&fromcol, NULL, (colnr_t *)&tocol);
  723.                 getvcol(wp, bot, &from, NULL, &to);
  724.                 if ((int)from < fromcol)
  725.                     fromcol = from;
  726.                 if ((int)to > tocol)
  727.                     tocol = to;
  728.                 ++tocol;
  729.  
  730.                 if (wp->w_curswant == MAXCOL)
  731.                     tocol = MAXCOL;
  732.             }
  733.         }
  734.         else                            /* non-block mode */
  735.         {
  736.             if (lnum > top->lnum && lnum <= bot->lnum)
  737.                 fromcol = 0;
  738.             else if (lnum == top->lnum)
  739.                 getvcol(wp, top, (colnr_t *)&fromcol, NULL, NULL);
  740.             if (lnum == bot->lnum)
  741.             {
  742.                 getvcol(wp, bot, NULL, NULL, (colnr_t *)&tocol);
  743.                 ++tocol;
  744.             }
  745.  
  746.             if (VIsual_mode == 'V')        /* linewise */
  747.             {
  748.                 if (fromcol > 0)
  749.                     fromcol = 0;
  750.                 tocol = MAXCOL;
  751.             }
  752.         }
  753.             /* if the cursor can't be switched off, don't invert the
  754.              * character where the cursor is */
  755. #ifndef MSDOS
  756.         if (!highlight_match && *T_VI == NUL &&
  757.                             lnum == curwin->w_cursor.lnum && wp == curwin)
  758.             noinvcur = TRUE;
  759. #endif
  760.  
  761.         if (tocol <= (int)wp->w_leftcol)    /* inverting is left of screen */
  762.             fromcol = 0;
  763.                                         /* start of invert is left of screen */
  764.         else if (fromcol >= 0 && fromcol < (int)wp->w_leftcol)
  765.             fromcol = wp->w_leftcol;
  766.  
  767.         /* if inverting in this line, can't optimize cursor positioning */
  768.         if (fromcol >= 0)
  769.             canopt = FALSE;
  770.     }
  771.     /*
  772.      * handle incremental search position highlighting
  773.      */
  774.     else if (highlight_match && wp == curwin && search_match_len)
  775.     {
  776.         if (lnum == curwin->w_cursor.lnum)
  777.         {
  778.             getvcol(curwin, &(curwin->w_cursor),
  779.                                             (colnr_t *)&fromcol, NULL, NULL);
  780.             curwin->w_cursor.col += search_match_len;
  781.             getvcol(curwin, &(curwin->w_cursor),
  782.                                             (colnr_t *)&tocol, NULL, NULL);
  783.             curwin->w_cursor.col -= search_match_len;
  784.             canopt = FALSE;
  785.             if (fromcol == tocol)        /* do at least one character */
  786.                 tocol = fromcol + 1;    /* happens when past end of line */
  787.         }
  788.     }
  789.  
  790.     ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
  791.     if (!wp->w_p_wrap)        /* advance to first character to be displayed */
  792.     {
  793.         while ((colnr_t)vcol < wp->w_leftcol && *ptr)
  794.             vcol += win_chartabsize(wp, *ptr++, (colnr_t)vcol);
  795.         if ((colnr_t)vcol > wp->w_leftcol)
  796.         {
  797.             n_spaces = vcol - wp->w_leftcol;    /* begin with some spaces */
  798.             vcol = wp->w_leftcol;
  799.         }
  800.     }
  801.     screenp = LinePointers[screen_row];
  802. #ifdef RIGHTLEFT
  803.     if (wp->w_p_rl)
  804.     {
  805.         col = Columns - 1;                    /* col follows screenp here */
  806.         screenp += Columns - 1;
  807.     }
  808. #endif
  809.     if (wp->w_p_nu)
  810.     {
  811. #ifdef RIGHTLEFT
  812.         if (wp->w_p_rl)                        /* reverse line numbers */
  813.         {
  814.             char_u *c1, *c2, t;
  815.  
  816.             sprintf((char *)extra, " %-7ld", (long)lnum);
  817.             for (c1 = extra, c2 = extra + STRLEN(extra) - 1; c1 < c2;
  818.                                                                    c1++, c2--)
  819.             {
  820.                 t = *c1;
  821.                 *c1 = *c2;
  822.                 *c2 = t;
  823.             }
  824.         }
  825.         else
  826. #endif
  827.             sprintf((char *)extra, "%7ld ", (long)lnum);
  828.         p_extra = extra;
  829.         n_extra = 8;
  830.         vcol -= 8;        /* so vcol is 0 when line number has been printed */
  831.     }
  832.     else
  833.     {
  834.         p_extra = NULL;
  835.         n_extra = 0;
  836.     }
  837.     for (;;)
  838.     {
  839.         if (!canopt)    /* Visual or match highlighting in this line */
  840.         {
  841.             if (((vcol == fromcol && !(noinvcur &&
  842.                                            (colnr_t)vcol == wp->w_virtcol)) ||
  843.                     (noinvcur && (colnr_t)vcol == wp->w_virtcol + 1 &&
  844.                             vcol >= fromcol)) && vcol < tocol)
  845.                 start_highlight();        /* start highlighting */
  846.             else if (attributes && (vcol == tocol ||
  847.                                 (noinvcur && (colnr_t)vcol == wp->w_virtcol)))
  848.                 stop_highlight();        /* stop highlighting */
  849.         }
  850.  
  851.     /* Get the next character to put on the screen. */
  852.  
  853.         /*
  854.          * if 'showbreak' is set it contains the characters to put at the
  855.          * start of each broken line
  856.          */
  857.         if (
  858. #ifdef RIGHTLEFT
  859.             (wp->w_p_rl ? col == -1 : col == Columns)
  860. #else
  861.             col == Columns
  862. #endif
  863.             && (*ptr != NUL || (wp->w_p_list && n_extra == 0) ||
  864.                                         (n_extra && *p_extra) || n_spaces) &&
  865.                                               vcol != 0 && STRLEN(p_sbr) != 0)
  866.             showbreak = p_sbr;
  867.         if (showbreak != NULL)
  868.         {
  869.             c = *showbreak++;
  870.             if (*showbreak == NUL)
  871.                 showbreak = NULL;
  872.         }
  873.         /*
  874.          * The 'extra' array contains the extra stuff that is inserted to
  875.          * represent special characters (non-printable stuff).
  876.          */
  877.         else if (n_extra)
  878.         {
  879.             c = *p_extra++;
  880.             n_extra--;
  881.         }
  882.         else if (n_spaces)
  883.         {
  884.             c = ' ';
  885.             n_spaces--;
  886.         }
  887.         else
  888.         {
  889.             c = *ptr++;
  890.             /*
  891.              * Found last space before word: check for line break
  892.              */
  893.             if (wp->w_p_lbr && isbreak(c) && !isbreak(*ptr) && !wp->w_p_list)
  894.             {
  895.                 n_spaces = win_lbr_chartabsize(wp, ptr - 1,
  896.                                                      (colnr_t)vcol, NULL) - 1;
  897.                 if (vim_iswhite(c))
  898.                     c = ' ';
  899.             }
  900.             else if (!isprintchar(c))
  901.             {
  902.                 /*
  903.                  * when getting a character from the file, we may have to turn
  904.                  * it into something else on the way to putting it into
  905.                  * 'NextScreen'.
  906.                  */
  907.                 if (c == TAB && !wp->w_p_list)
  908.                 {
  909.                     /* tab amount depends on current column */
  910.                     n_spaces = (int)wp->w_buffer->b_p_ts -
  911.                                     vcol % (int)wp->w_buffer->b_p_ts - 1;
  912.                     c = ' ';
  913.                 }
  914.                 else if (c == NUL && wp->w_p_list)
  915.                 {
  916.                     p_extra = (char_u *)"";
  917.                     n_extra = 1;
  918.                     c = '$';
  919.                     --ptr;            /* put it back at the NUL */
  920.                 }
  921.                 else if (c != NUL)
  922.                 {
  923.                     p_extra = transchar(c);
  924.                     n_extra = charsize(c) - 1;
  925.                     c = *p_extra++;
  926.                 }
  927.             }
  928.         }
  929.  
  930.         if (c == NUL)
  931.         {
  932.             if (attributes)
  933.             {
  934.                 /* invert at least one char, used for Visual and empty line or
  935.                  * highlight match at end of line. If it's beyond the last
  936.                  * char on the screen, just overwrite that one (tricky!) */
  937.                 if (vcol == fromcol)
  938.                 {
  939. #ifdef RIGHTLEFT
  940.                     if (wp->w_p_rl)
  941.                     {
  942.                         if (col < 0)
  943.                         {
  944.                             ++screenp;
  945.                             ++col;
  946.                         }
  947.                     }
  948.                     else
  949. #endif
  950.                     {
  951.                         if (col >= Columns)
  952.                         {
  953.                             --screenp;
  954.                             --col;
  955.                         }
  956.                     }
  957.                     if (*screenp != ' ' || *(screenp + Columns) != attributes)
  958.                     {
  959.                             *screenp = ' ';
  960.                             *(screenp + Columns) = attributes;
  961.                             screen_char(screenp, screen_row, col);
  962.                     }
  963. #ifdef RIGHTLEFT
  964.                     if (wp->w_p_rl)
  965.                     {
  966.                         --screenp;
  967.                         --col;
  968.                     }
  969.                     else
  970. #endif
  971.                     {
  972.                         ++screenp;
  973.                         ++col;
  974.                     }
  975.                 }
  976.                 stop_highlight();
  977.             }
  978.             /* 
  979.              * blank out the rest of this row, if necessary
  980.              */
  981. #ifdef RIGHTLEFT
  982.             if (wp->w_p_rl)
  983.             {
  984.                 while (col >= 0 && *screenp == ' ' &&
  985.                                                     *(screenp + Columns) == 0)
  986.                 {
  987.                     --screenp;
  988.                     --col;
  989.                 }
  990.                 if (col >= 0)
  991.                     screen_fill(screen_row, screen_row + 1,
  992.                                                         0, col + 1, ' ', ' ');
  993.             }
  994.             else
  995. #endif
  996.             {
  997.                 while (col < Columns && *screenp == ' ' &&
  998.                                                     *(screenp + Columns) == 0)
  999.                 {
  1000.                     ++screenp;
  1001.                     ++col;
  1002.                 }
  1003.                 if (col < Columns)
  1004.                     screen_fill(screen_row, screen_row + 1,
  1005.                                                 col, (int)Columns, ' ', ' ');
  1006.             }
  1007.             row++;
  1008.             break;
  1009.         }
  1010.         if (
  1011. #ifdef RIGHTLEFT
  1012.             wp->w_p_rl ? (col < 0) : 
  1013. #endif
  1014.                                     (col >= Columns)
  1015.                                                     )
  1016.         {
  1017.             col = 0;
  1018.             ++row;
  1019.             ++screen_row;
  1020.             if (!wp->w_p_wrap)
  1021.                 break;
  1022.             if (row == endrow)        /* line got too long for screen */
  1023.             {
  1024.                 ++row;
  1025.                 break;
  1026.             }
  1027.             screenp = LinePointers[screen_row];
  1028. #ifdef RIGHTLEFT
  1029.             if (wp->w_p_rl)
  1030.             {
  1031.                 col = Columns - 1;        /* col is not used if breaking! */
  1032.                 screenp += Columns - 1;
  1033.             }
  1034. #endif
  1035.         }
  1036.  
  1037.         /*
  1038.          * Store the character in NextScreen.
  1039.          */
  1040.         if (*screenp != c || *(screenp + Columns) != attributes)
  1041.         {
  1042.             /*
  1043.              * Special trick to make copy/paste of wrapped lines work with
  1044.              * xterm/screen:
  1045.              *   If the first column is to be written, write the preceding
  1046.              *   char twice.  This will work with all terminal types
  1047.              *   (regardless of the xn,am settings).
  1048.              * Only do this on a fast tty.
  1049.              */
  1050.             if (p_tf && row > startrow && col == 0 &&
  1051.                     LinePointers[screen_row - 1][Columns - 1 + Columns] ==
  1052.                         attributes)
  1053.             {
  1054.                 if (screen_cur_row != screen_row - 1 ||
  1055.                                                     screen_cur_col != Columns)
  1056.                     screen_char(LinePointers[screen_row - 1] + Columns - 1,
  1057.                                           screen_row - 1, (int)(Columns - 1));
  1058.                 screen_char(LinePointers[screen_row - 1] + Columns - 1,
  1059.                                                 screen_row - 1, (int)Columns);    
  1060.                 screen_start();
  1061.             }
  1062.  
  1063.             *screenp = c;
  1064.             *(screenp + Columns) = attributes;
  1065.             screen_char(screenp, screen_row, col);
  1066.         }
  1067. #ifdef RIGHTLEFT
  1068.         if (wp->w_p_rl)
  1069.         {
  1070.             --screenp;
  1071.             --col;
  1072.         }
  1073.         else
  1074. #endif
  1075.         {
  1076.             ++screenp;
  1077.             ++col;
  1078.         }
  1079.         ++vcol;
  1080.             /* stop before '$' of change command */
  1081.         if (wp == curwin && dollar_vcol && vcol >= (long)wp->w_virtcol)
  1082.             break;
  1083.     }
  1084.  
  1085.     stop_highlight();
  1086.     return (row);
  1087. }
  1088.  
  1089. /*
  1090.  * Called when p_dollar is set: display a '$' at the end of the changed text
  1091.  * Only works when cursor is in the line that changes.
  1092.  */
  1093.     void
  1094. display_dollar(col)
  1095.     colnr_t        col;
  1096. {
  1097.     colnr_t    save_col;
  1098.  
  1099.     if (RedrawingDisabled)
  1100.         return;
  1101.  
  1102.     cursor_off();
  1103.     save_col = curwin->w_cursor.col;
  1104.     curwin->w_cursor.col = col;
  1105.     curs_columns(FALSE);
  1106.     if (!curwin->w_p_wrap)
  1107.         curwin->w_col -= curwin->w_leftcol;
  1108.     if (curwin->w_col < Columns)
  1109.     {
  1110.         screen_msg((char_u *)"$", curwin->w_winpos + curwin->w_row,
  1111. #ifdef RIGHTLEFT
  1112.                 curwin->w_p_rl ? (int)Columns - 1 - curwin->w_col :
  1113. #endif
  1114.                                                                curwin->w_col);
  1115.         dollar_vcol = curwin->w_virtcol;
  1116.     }
  1117.     curwin->w_cursor.col = save_col;
  1118. }
  1119.  
  1120. /*
  1121.  * Call this function before moving the cursor from the normal insert position
  1122.  * in insert mode.
  1123.  */
  1124.     void
  1125. undisplay_dollar()
  1126. {
  1127.     if (dollar_vcol)
  1128.     {
  1129.         dollar_vcol = 0;
  1130.         updateline();
  1131.     }
  1132. }
  1133.  
  1134. /*
  1135.  * output a single character directly to the screen
  1136.  * update NextScreen
  1137.  */
  1138.     void
  1139. screen_outchar(c, row, col)
  1140.     int        c;
  1141.     int        row, col;
  1142. {
  1143.     char_u        buf[2];
  1144.  
  1145.     buf[0] = c;
  1146.     buf[1] = NUL;
  1147.     screen_msg(buf, row, col);
  1148. }
  1149.     
  1150. /*
  1151.  * put string '*text' on the screen at position 'row' and 'col'
  1152.  * update NextScreen
  1153.  * Note: only outputs within one row, message is truncated at screen boundary!
  1154.  * Note: if NextScreen, row and/or col is invalid, nothing is done.
  1155.  */
  1156.     void
  1157. screen_msg(text, row, col)
  1158.     char_u    *text;
  1159.     int        row;
  1160.     int        col;
  1161. {
  1162.     char_u    *screenp;
  1163.  
  1164.     if (NextScreen != NULL && row < Rows)            /* safety check */
  1165.     {
  1166.         screenp = LinePointers[row] + col;
  1167.         while (*text && col < Columns)
  1168.         {
  1169.             if (*screenp != *text || *(screenp + Columns) != attributes)
  1170.             {
  1171.                 *screenp = *text;
  1172.                 *(screenp + Columns) = attributes;
  1173.                 screen_char(screenp, row, col);
  1174.             }
  1175.             ++screenp;
  1176.             ++col;
  1177.             ++text;
  1178.         }
  1179.     }
  1180. }
  1181.  
  1182. /*
  1183.  * Reset cursor position. Use whenever cursor was moved because of outputting
  1184.  * something directly to the screen (shell commands) or a terminal control
  1185.  * code.
  1186.  */
  1187.     void
  1188. screen_start()
  1189. {
  1190.     screen_cur_row = screen_cur_col = 9999;
  1191. }
  1192.  
  1193. /*
  1194.  * set_highlight - set highlight depending on 'highlight' option and context.
  1195.  *
  1196.  * return FAIL if highlighting is not possible, OK otherwise
  1197.  */
  1198.     int
  1199. set_highlight(context)
  1200.     int        context;
  1201. {
  1202.     int        i;
  1203.     int        mode;
  1204.     char_u    *p;
  1205.  
  1206.     /*
  1207.      * Try to find the mode in the 'highlight' option.
  1208.      * If not found, try the default for the 'highlight' option.
  1209.      * If still not found, use 'r' (should not happen).
  1210.      */
  1211.     mode = 'r';
  1212.     for (i = 0; i < 2; ++i)
  1213.     {
  1214.         if (i)
  1215.             p = get_highlight_default();
  1216.         else
  1217.             p = p_hl;
  1218.         if (p == NULL)
  1219.             continue;
  1220.  
  1221.         while (*p)
  1222.         {
  1223.             if (*p == context)                /* found what we are looking for */
  1224.                 break;
  1225.             while (*p && *p != ',')            /* skip to comma */
  1226.                 ++p;
  1227.             p = skip_to_option_part(p);        /* skip comma and spaces */
  1228.         }
  1229.         if (p[0] && p[1])
  1230.         {
  1231.             mode = p[1];
  1232.             break;
  1233.         }
  1234.     }
  1235.  
  1236.     switch (mode)
  1237.     {
  1238.         case 'b':    highlight = T_MD;        /* bold */
  1239.                     unhighlight = T_ME;
  1240.                     highlight_attr = CHAR_BOLD;
  1241.                     break;
  1242.         case 's':    highlight = T_SO;        /* standout */
  1243.                     unhighlight = T_SE;
  1244.                     highlight_attr = CHAR_STDOUT;
  1245.                     break;
  1246.         case 'n':    highlight = NULL;        /* no highlighting */
  1247.                     unhighlight = NULL;
  1248.                     highlight_attr = 0;
  1249.                     break;
  1250.         case 'u':    highlight = T_US;        /* underline */
  1251.                     unhighlight = T_UE;
  1252.                     highlight_attr = CHAR_UNDERL;
  1253.                     break;
  1254.         case 'i':    highlight = T_CZH;        /* italic */
  1255.                     unhighlight = T_CZR;
  1256.                     highlight_attr = CHAR_ITALIC;
  1257.                     break;
  1258.         default:    highlight = T_MR;        /* reverse (invert) */
  1259.                     unhighlight = T_ME;
  1260.                     highlight_attr = CHAR_INVERT;
  1261.                     break;
  1262.     }
  1263.     if (highlight == NULL || *highlight == NUL ||
  1264.                         unhighlight == NULL || *unhighlight == NUL)
  1265.     {
  1266.         highlight = NULL;
  1267.         return FAIL;
  1268.     }
  1269.     return OK;
  1270. }
  1271.  
  1272.     void
  1273. start_highlight()
  1274. {
  1275.     if (full_screen &&
  1276. #ifdef WIN32
  1277.                         termcap_active &&
  1278. #endif
  1279.                                             highlight != NULL)
  1280.     {
  1281.         outstr(highlight);
  1282.         attributes = highlight_attr;
  1283.     }
  1284. }
  1285.  
  1286.     void
  1287. stop_highlight()
  1288. {
  1289.     if (attributes)
  1290.     {
  1291.         outstr(unhighlight);
  1292.         attributes = 0;
  1293.     }
  1294. }
  1295.  
  1296. /*
  1297.  * variables used for one level depth of highlighting
  1298.  * Used for "-- More --" message.
  1299.  */
  1300.  
  1301. static char_u    *old_highlight = NULL;
  1302. static char_u    *old_unhighlight = NULL;
  1303. static int        old_highlight_attr = 0;
  1304.  
  1305.     void
  1306. remember_highlight()
  1307. {
  1308.     old_highlight = highlight;
  1309.     old_unhighlight = unhighlight;
  1310.     old_highlight_attr = highlight_attr;
  1311. }
  1312.  
  1313.     void
  1314. recover_old_highlight()
  1315. {
  1316.     highlight = old_highlight;
  1317.     unhighlight = old_unhighlight;
  1318.     highlight_attr = old_highlight_attr;
  1319. }
  1320.  
  1321. /*
  1322.  * put character '*p' on the screen at position 'row' and 'col'
  1323.  */
  1324.     static void
  1325. screen_char(p, row, col)
  1326.     char_u    *p;
  1327.     int     row;
  1328.     int     col;
  1329. {
  1330.     int            c;
  1331.     int            noinvcurs;
  1332.  
  1333.     /*
  1334.      * Outputting the last character on the screen may scrollup the screen.
  1335.      * Don't to it!
  1336.      */
  1337.     if (col == Columns - 1 && row == Rows - 1)
  1338.         return;
  1339.     if (screen_cur_col != col || screen_cur_row != row)
  1340.     {
  1341.         /* check if no cursor movement is allowed in standout mode */
  1342.         if (attributes && !p_wiv && *T_MS == NUL)
  1343.             noinvcurs = 7;
  1344.         else
  1345.             noinvcurs = 0;
  1346.  
  1347.         /*
  1348.          * If we're on the same row (which happens a lot!), try to
  1349.          * avoid a windgoto().
  1350.          * If we are only a few characters off, output the
  1351.          * characters. That is faster than cursor positioning.
  1352.          * This can't be used when switching between inverting and not
  1353.          * inverting.
  1354.          */
  1355.         if (screen_cur_row == row && screen_cur_col < col)
  1356.         {
  1357.             register int i;
  1358.  
  1359.             i = col - screen_cur_col;
  1360.             if (i <= 4 + noinvcurs)
  1361.             {
  1362.                 /* stop at the first character that has different attributes
  1363.                  * from the ones that are active */
  1364.                 while (i && *(p - i + Columns) == attributes)
  1365.                 {
  1366.                     c = *(p - i--);
  1367.                     outchar(c);
  1368.                 }
  1369.             }
  1370.             if (i)
  1371.             {
  1372.                 if (noinvcurs)
  1373.                     stop_highlight();
  1374.             
  1375.                 if (*T_CRI != NUL)    /* use tgoto interface! jw */
  1376.                     OUTSTR(tgoto((char *)T_CRI, 0, i));
  1377.                 else
  1378.                     windgoto(row, col);
  1379.             
  1380.                 if (noinvcurs)
  1381.                     start_highlight();
  1382.             }
  1383.         }
  1384.         /*
  1385.          * If the cursor is at the line above where we want to be, use CR LF,
  1386.          * this is quicker than windgoto().
  1387.          * Don't do this if the cursor went beyond the last column, the cursor
  1388.          * position is unknown then (some terminals wrap, some don't )
  1389.          */
  1390.         else if (screen_cur_row + 1 == row && col == 0 &&
  1391.                                                      screen_cur_col < Columns)
  1392.         {
  1393.             if (noinvcurs)
  1394.                 stop_highlight();
  1395.             outchar('\n');
  1396.             if (noinvcurs)
  1397.                 start_highlight();
  1398.         }
  1399.         else
  1400.         {
  1401.             if (noinvcurs)
  1402.                 stop_highlight();
  1403.             windgoto(row, col);
  1404.             if (noinvcurs)
  1405.                 start_highlight();
  1406.         }
  1407.         screen_cur_row = row;
  1408.         screen_cur_col = col;
  1409.     }
  1410.  
  1411.     /*
  1412.      * For weird invert mechanism: output (un)highlight before every char
  1413.      * Lots of extra output, but works.
  1414.      */
  1415.     if (p_wiv)
  1416.     {
  1417.         if (attributes)                                      
  1418.             outstr(highlight);                            
  1419.         else if (full_screen)                                            
  1420.             outstr(unhighlight);
  1421.     }
  1422.     outchar(*p);
  1423.     screen_cur_col++;
  1424. }
  1425.  
  1426. /*
  1427.  * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
  1428.  * with character 'c1' in first column followed by 'c2' in the other columns.
  1429.  */
  1430.     void
  1431. screen_fill(start_row, end_row, start_col, end_col, c1, c2)
  1432.     int     start_row, end_row;
  1433.     int        start_col, end_col;
  1434.     int        c1, c2;
  1435. {
  1436.     int                row;
  1437.     int                col;
  1438.     char_u            *screenp;
  1439.     char_u            *attrp;
  1440.     int                did_delete;
  1441.     int                c;
  1442.  
  1443.     if (end_row > Rows)                /* safety check */
  1444.         end_row = Rows;
  1445.     if (end_col > Columns)            /* safety check */
  1446.         end_col = Columns;
  1447.     if (NextScreen == NULL ||
  1448.             start_row >= end_row || start_col >= end_col)    /* nothing to do */
  1449.         return;
  1450.  
  1451.     for (row = start_row; row < end_row; ++row)
  1452.     {
  1453.             /* try to use delete-line termcap code */
  1454.         did_delete = FALSE;
  1455.         if (attributes == 0 && c2 == ' ' && end_col == Columns && *T_CE != NUL
  1456. #ifdef RIGHTLEFT
  1457.                     && !rightleft
  1458. #endif
  1459.                                     )
  1460.         {
  1461.             /*
  1462.              * check if we really need to clear something
  1463.              */
  1464.             col = start_col;
  1465.             screenp = LinePointers[row] + start_col;
  1466.             if (c1 != ' ')                        /* don't clear first char */
  1467.             {
  1468.                 ++col;
  1469.                 ++screenp;
  1470.             }
  1471.  
  1472.             /* skip blanks (used often, keep it fast!) */
  1473.             attrp = screenp + Columns;
  1474.             while (col < end_col && *screenp == ' ' && *attrp == 0)
  1475.             {
  1476.                 ++col;
  1477.                 ++screenp;
  1478.                 ++attrp;
  1479.             }
  1480.             if (col < end_col)            /* something to be cleared */
  1481.             {
  1482.                 windgoto(row, col);        /* clear rest of this screen line */
  1483.                 outstr(T_CE);
  1484.                 screen_start();            /* don't know where cursor is now */
  1485.                 col = end_col - col;
  1486.                 while (col--)            /* clear chars in NextScreen */
  1487.                 {
  1488.                     *attrp++ = 0;
  1489.                     *screenp++ = ' ';
  1490.                 }
  1491.             }
  1492.             did_delete = TRUE;            /* the chars are cleared now */
  1493.         }
  1494.  
  1495.         screenp = LinePointers[row] +
  1496. #ifdef RIGHTLEFT
  1497.             (rightleft ? (int)Columns - 1 - start_col : start_col);
  1498. #else
  1499.                                                     start_col;
  1500. #endif
  1501.         c = c1;
  1502.         for (col = start_col; col < end_col; ++col)
  1503.         {
  1504.             if (*screenp != c || *(screenp + Columns) != attributes)
  1505.             {
  1506.                 *screenp = c;
  1507.                 *(screenp + Columns) = attributes;
  1508.                 if (!did_delete || c != ' ')
  1509.                     screen_char(screenp, row,
  1510. #ifdef RIGHTLEFT
  1511.                             rightleft ? Columns - 1 - col :
  1512. #endif
  1513.                                                             col);
  1514.             }
  1515. #ifdef RIGHTLEFT
  1516.             if (rightleft)
  1517.                 --screenp;
  1518.             else
  1519. #endif
  1520.                 ++screenp;
  1521.             if (col == start_col)
  1522.             {
  1523.                 if (did_delete)
  1524.                     break;
  1525.                 c = c2;
  1526.             }
  1527.         }
  1528.         if (row == Rows - 1)            /* overwritten the command line */
  1529.         {
  1530.             redraw_cmdline = TRUE;
  1531.             if (c1 == ' ' && c2 == ' ')
  1532.                 clear_cmdline = FALSE;    /* command line has been cleared */
  1533.         }
  1534.     }
  1535. }
  1536.  
  1537. /*
  1538.  * recompute all w_botline's. Called after Rows changed.
  1539.  */
  1540.     void
  1541. comp_Botline_all()
  1542. {
  1543.     WIN        *wp;
  1544.  
  1545.     for (wp = firstwin; wp; wp = wp->w_next)
  1546.         comp_Botline(wp);
  1547. }
  1548.  
  1549. /*
  1550.  * compute wp->w_botline. Can be called after wp->w_topline changed.
  1551.  */
  1552.     void
  1553. comp_Botline(wp)
  1554.     WIN            *wp;
  1555. {
  1556.     comp_Botline_sub(wp, wp->w_topline, 0);
  1557. }
  1558.  
  1559. /*
  1560.  * Compute wp->w_botline, may have a start at the cursor position.
  1561.  * Code shared between comp_Botline() and cursupdate().
  1562.  */
  1563.     static void
  1564. comp_Botline_sub(wp, lnum, done)
  1565.     WIN            *wp;
  1566.     linenr_t    lnum;
  1567.     int            done;
  1568. {
  1569.     int            n;
  1570.  
  1571.     for ( ; lnum <= wp->w_buffer->b_ml.ml_line_count; ++lnum)
  1572.     {
  1573.         n = plines_win(wp, lnum);
  1574.         if (done + n > wp->w_height)
  1575.             break;
  1576.         done += n;
  1577.     }
  1578.  
  1579.     /* wp->w_botline is the line that is just below the window */
  1580.     wp->w_botline = lnum;
  1581.  
  1582.     /* Also set wp->w_empty_rows, otherwise scroll_cursor_bot() won't work */
  1583.     if (done == 0)
  1584.         wp->w_empty_rows = 0;        /* single line that doesn't fit */
  1585.     else
  1586.         wp->w_empty_rows = wp->w_height - done;
  1587. }
  1588.  
  1589.     void
  1590. screenalloc(clear)
  1591.     int        clear;
  1592. {
  1593.     register int    new_row, old_row;
  1594.     WIN                *wp;
  1595.     int                outofmem = FALSE;
  1596.     int                len;
  1597.     char_u            *new_NextScreen;
  1598.     char_u            **new_LinePointers;
  1599.  
  1600.     /*
  1601.      * Allocation of the screen buffers is done only when the size changes
  1602.      * and when Rows and Columns have been set and we are doing full screen
  1603.      * stuff.
  1604.      */
  1605.     if ((NextScreen != NULL && Rows == screen_Rows && Columns == screen_Columns)
  1606.                             || Rows == 0 || Columns == 0 || !full_screen)
  1607.         return;
  1608.  
  1609.     comp_col();            /* recompute columns for shown command and ruler */
  1610.  
  1611.     /*
  1612.      * We're changing the size of the screen.
  1613.      * - Allocate new arrays for NextScreen.
  1614.      * - Move lines from the old arrays into the new arrays, clear extra
  1615.      *   lines (unless the screen is going to be cleared).
  1616.      * - Free the old arrays.
  1617.      */
  1618.     for (wp = firstwin; wp; wp = wp->w_next)
  1619.         win_free_lsize(wp);
  1620.  
  1621.     new_NextScreen = (char_u *)malloc((size_t) (Rows * Columns * 2));
  1622.     new_LinePointers = (char_u **)malloc(sizeof(char_u *) * Rows);
  1623.  
  1624.     for (wp = firstwin; wp; wp = wp->w_next)
  1625.     {
  1626.         if (win_alloc_lsize(wp) == FAIL)
  1627.         {
  1628.             outofmem = TRUE;
  1629.             break;
  1630.         }
  1631.     }
  1632.  
  1633.     if (new_NextScreen == NULL || new_LinePointers == NULL || outofmem)
  1634.     {
  1635.         do_outofmem_msg();
  1636.         vim_free(new_NextScreen);
  1637.         new_NextScreen = NULL;
  1638.     }
  1639.     else
  1640.     {
  1641.         for (new_row = 0; new_row < Rows; ++new_row)
  1642.         {
  1643.             new_LinePointers[new_row] = new_NextScreen + new_row * Columns * 2;
  1644.  
  1645.             /*
  1646.              * If the screen is not going to be cleared, copy as much as
  1647.              * possible from the old screen to the new one and clear the rest
  1648.              * (used when resizing the window at the "--more--" prompt or when
  1649.              * executing an external command, for the GUI).
  1650.              */
  1651.             if (!clear)
  1652.             {
  1653.                 lineclear(new_LinePointers[new_row]);
  1654.                 old_row = new_row + (screen_Rows - Rows);
  1655.                 if (old_row >= 0)
  1656.                 {
  1657.                     if (screen_Columns < Columns)
  1658.                         len = screen_Columns;
  1659.                     else
  1660.                         len = Columns;
  1661.                     vim_memmove(new_LinePointers[new_row],
  1662.                             LinePointers[old_row], (size_t)len);
  1663.                     vim_memmove(new_LinePointers[new_row] + Columns,
  1664.                             LinePointers[old_row] + screen_Columns, (size_t)len);
  1665.                 }
  1666.             }
  1667.         }
  1668.     }
  1669.  
  1670.     vim_free(NextScreen);
  1671.     vim_free(LinePointers);
  1672.     NextScreen = new_NextScreen;
  1673.     LinePointers = new_LinePointers;
  1674.  
  1675.     must_redraw = CLEAR;        /* need to clear the screen later */
  1676.     if (clear)
  1677.         screenclear2();
  1678.  
  1679. #ifdef USE_GUI
  1680.     else if (gui.in_use && NextScreen != NULL && Rows != screen_Rows)
  1681.     {
  1682.         gui_redraw_block(0, 0, Rows - 1, Columns - 1);
  1683.         /*
  1684.          * Adjust the position of the cursor, for when executing an external
  1685.          * command.
  1686.          */
  1687.         if (msg_row >= Rows)                /* Rows got smaller */
  1688.             msg_row = Rows - 1;                /* put cursor at last row */
  1689.         else if (Rows > screen_Rows)        /* Rows got bigger */
  1690.             msg_row += Rows - screen_Rows;    /* put cursor in same place */
  1691.         if (msg_col >= Columns)                /* Columns got smaller */
  1692.             msg_col = Columns - 1;            /* put cursor at last column */
  1693.     }
  1694. #endif
  1695.  
  1696.     screen_Rows = Rows;
  1697.     screen_Columns = Columns;
  1698. }
  1699.  
  1700.     void
  1701. screenclear()
  1702. {
  1703.     if (emsg_on_display)
  1704.     {
  1705.         mch_delay(1000L, TRUE);
  1706.         emsg_on_display = FALSE;
  1707.     }
  1708.     screenalloc(FALSE);        /* allocate screen buffers if size changed */
  1709.     screenclear2();            /* clear the screen */
  1710. }
  1711.  
  1712.     static void
  1713. screenclear2()
  1714. {
  1715.     int        i;
  1716.  
  1717.     if (starting || NextScreen == NULL)
  1718.         return;
  1719.  
  1720.     outstr(T_CL);                /* clear the display */
  1721.  
  1722.                                 /* blank out NextScreen */
  1723.     for (i = 0; i < Rows; ++i)
  1724.         lineclear(LinePointers[i]);
  1725.  
  1726.     screen_cleared = TRUE;            /* can use contents of NextScreen now */
  1727.  
  1728.     win_rest_invalid(firstwin);
  1729.     clear_cmdline = FALSE;
  1730.     redraw_cmdline = TRUE;
  1731.     if (must_redraw == CLEAR)        /* no need to clear again */
  1732.         must_redraw = NOT_VALID;
  1733.     compute_cmdrow();
  1734.     msg_pos((int)Rows - 1, 0);        /* put cursor on last line for messages */
  1735.     screen_start();                    /* don't know where cursor is now */
  1736.     msg_scrolled = 0;                /* can't scroll back */
  1737.     msg_didany = FALSE;
  1738.     msg_didout = FALSE;
  1739. }
  1740.  
  1741. /*
  1742.  * Clear one line in NextScreen.
  1743.  */
  1744.     static void
  1745. lineclear(p)
  1746.     char_u    *p;
  1747. {
  1748.     (void)vim_memset(p, ' ', (size_t)Columns);
  1749.     (void)vim_memset(p + Columns, 0, (size_t)Columns);
  1750. }
  1751.  
  1752. /*
  1753.  * check cursor for a valid lnum
  1754.  */
  1755.     void
  1756. check_cursor()
  1757. {
  1758.     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  1759.         curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  1760.     if (curwin->w_cursor.lnum <= 0)
  1761.         curwin->w_cursor.lnum = 1;
  1762. }
  1763.  
  1764.     void
  1765. cursupdate()
  1766. {
  1767.     linenr_t        lnum;
  1768.     long             line_count;
  1769.     int             sline;
  1770.     int                done;
  1771.     int             temp;
  1772.  
  1773.     if (!screen_valid(TRUE))
  1774.         return;
  1775.  
  1776.     /*
  1777.      * Make sure the cursor is on a valid line number
  1778.      */
  1779.     check_cursor();
  1780.  
  1781.     /*
  1782.      * If the buffer is empty, always set topline to 1.
  1783.      */
  1784.     if (bufempty())             /* special case - file is empty */
  1785.     {
  1786.         curwin->w_topline = 1;
  1787.         curwin->w_cursor.lnum = 1;
  1788.         curwin->w_cursor.col = 0;
  1789.         curwin->w_lsize[0] = 0;
  1790.         if (curwin->w_lsize_valid == 0)    /* don't know about screen contents */
  1791.             updateScreen(NOT_VALID);
  1792.         curwin->w_lsize_valid = 1;
  1793.     }
  1794.  
  1795.     /*
  1796.      * If the cursor is above the top of the window, scroll the window to put
  1797.      * it at the top of the window.
  1798.      * If we weren't very close to begin with, we scroll to put the cursor in
  1799.      * the middle of the window.
  1800.      */
  1801.     else if (curwin->w_cursor.lnum < curwin->w_topline + p_so &&
  1802.                                                         curwin->w_topline > 1)
  1803.     {
  1804.         temp = curwin->w_height / 2 - 1;
  1805.         if (temp < 2)
  1806.             temp = 2;
  1807.                                 /* not very close, put cursor halfway screen */
  1808.         if (curwin->w_topline + p_so - curwin->w_cursor.lnum >= temp)
  1809.             scroll_cursor_halfway(FALSE);
  1810.         else
  1811.             scroll_cursor_top((int)p_sj, FALSE);
  1812.         updateScreen(VALID);
  1813.     }
  1814.  
  1815.     /*
  1816.      * If the cursor is below the bottom of the window, scroll the window
  1817.      * to put the cursor on the window. If the cursor is less than a
  1818.      * windowheight down compute the number of lines at the top which have
  1819.      * the same or more rows than the rows of the lines below the bottom.
  1820.      * Note: After curwin->w_botline was computed lines may have been
  1821.      * added or deleted, it may be greater than ml_line_count.
  1822.      */
  1823.     else if ((long)curwin->w_cursor.lnum >= (long)curwin->w_botline - p_so &&
  1824.                                 curwin->w_botline <= curbuf->b_ml.ml_line_count)
  1825.     {
  1826.         line_count = curwin->w_cursor.lnum - curwin->w_botline + 1 + p_so;
  1827.         if (line_count <= curwin->w_height + 1)
  1828.             scroll_cursor_bot((int)p_sj, FALSE);
  1829.         else
  1830.             scroll_cursor_halfway(FALSE);
  1831.         updateScreen(VALID);
  1832.     }
  1833.  
  1834.     /*
  1835.      * If the window contents is unknown, need to update the screen.
  1836.      */
  1837.     else if (curwin->w_lsize_valid == 0)
  1838.         updateScreen(NOT_VALID);
  1839.  
  1840.     /*
  1841.      * Figure out the row number of the cursor line.
  1842.      * This is used often, keep it fast!
  1843.      */
  1844.     curwin->w_row = sline = 0;
  1845.                                             /* curwin->w_lsize[] invalid */
  1846.     if (RedrawingDisabled || curwin->w_lsize_valid == 0)
  1847.     {
  1848.         done = 0;
  1849.         for (lnum = curwin->w_topline; lnum != curwin->w_cursor.lnum; ++lnum)
  1850.             done += plines(lnum);
  1851.         curwin->w_row = done;
  1852.  
  1853.         /*
  1854.          * Also need to compute w_botline and w_empty_rows, because
  1855.          * updateScreen() will not have done that.
  1856.          */
  1857.         comp_Botline_sub(curwin, lnum, done);
  1858.     }
  1859.     else
  1860.     {
  1861.         for (done = curwin->w_cursor.lnum - curwin->w_topline; done > 0; --done)
  1862.             curwin->w_row += curwin->w_lsize[sline++];
  1863.     }
  1864.  
  1865.     curwin->w_cline_row = curwin->w_row;
  1866.     curwin->w_col = curwin->w_virtcol = 0;
  1867.     if (!RedrawingDisabled && sline > curwin->w_lsize_valid)
  1868.                                 /* Should only happen with a line that is too */
  1869.                                 /* long to fit on the last screen line. */
  1870.         curwin->w_cline_height = 0;
  1871.     else
  1872.     {
  1873.                             /* curwin->w_lsize[] invalid */
  1874.         if (RedrawingDisabled || curwin->w_lsize_valid == 0)
  1875.             curwin->w_cline_height = plines(curwin->w_cursor.lnum);
  1876.         else
  1877.             curwin->w_cline_height = curwin->w_lsize[sline];
  1878.                             /* compute curwin->w_virtcol and curwin->w_col */
  1879.         curs_columns(!RedrawingDisabled);
  1880.         if (must_redraw)
  1881.             updateScreen(must_redraw);
  1882.     }
  1883.  
  1884.     if (curwin->w_set_curswant)
  1885.     {
  1886.         curwin->w_curswant = curwin->w_virtcol;
  1887.         curwin->w_set_curswant = FALSE;
  1888.     }
  1889. }
  1890.  
  1891. /*
  1892.  * Recompute topline to put the cursor at the top of the window.
  1893.  * Scroll at least "min_scroll" lines.
  1894.  * If "always" is TRUE, always set topline (for "zt").
  1895.  */
  1896.     void
  1897. scroll_cursor_top(min_scroll, always)
  1898.     int        min_scroll;
  1899.     int        always;
  1900. {
  1901.     int        scrolled = 0;
  1902.     int        extra = 0;
  1903.     int        used;
  1904.     int        i;
  1905.     int        sline;        /* screen line for cursor */
  1906.  
  1907.     /*
  1908.      * Decrease topline until:
  1909.      * - it has become 1
  1910.      * - (part of) the cursor line is moved off the screen or
  1911.      * - moved at least 'scrolljump' lines and
  1912.      * - at least 'scrolloff' lines above and below the cursor
  1913.      */
  1914.     used = plines(curwin->w_cursor.lnum);
  1915.     for (sline = 1; sline < curwin->w_cursor.lnum; ++sline)
  1916.     {
  1917.         i = plines(curwin->w_cursor.lnum - sline);
  1918.         used += i;
  1919.         extra += i;
  1920.         if (extra <= p_so &&
  1921.                    curwin->w_cursor.lnum + sline < curbuf->b_ml.ml_line_count)
  1922.             used += plines(curwin->w_cursor.lnum + sline);
  1923.         if (used > curwin->w_height)
  1924.             break;
  1925.         if (curwin->w_cursor.lnum - sline < curwin->w_topline)
  1926.             scrolled += i;
  1927.  
  1928.         /*
  1929.          * If scrolling is needed, scroll at least 'sj' lines.
  1930.          */
  1931.         if ((curwin->w_cursor.lnum - (sline - 1) >= curwin->w_topline ||
  1932.                                       scrolled >= min_scroll) && extra > p_so)
  1933.             break;
  1934.     }
  1935.  
  1936.     /*
  1937.      * If we don't have enough space, put cursor in the middle.
  1938.      * This makes sure we get the same position when using "k" and "j"
  1939.      * in a small window.
  1940.      */
  1941.     if (used > curwin->w_height)
  1942.         scroll_cursor_halfway(FALSE);
  1943.     else
  1944.     {
  1945.         /*
  1946.          * If "always" is FALSE, only adjust topline to a lower value, higher
  1947.          * value may happen with wrapping lines
  1948.          */
  1949.         if (curwin->w_cursor.lnum - (sline - 1) < curwin->w_topline || always)
  1950.             curwin->w_topline = curwin->w_cursor.lnum - (sline - 1);
  1951.         if (curwin->w_topline > curwin->w_cursor.lnum)
  1952.             curwin->w_topline = curwin->w_cursor.lnum;
  1953.     }
  1954. }
  1955.  
  1956. /*
  1957.  * Recompute topline to put the cursor at the bottom of the window.
  1958.  * Scroll at least "min_scroll" lines.
  1959.  * If "set_topline" is TRUE, set topline and botline first (for "zb").
  1960.  * This is messy stuff!!!
  1961.  */
  1962.     void
  1963. scroll_cursor_bot(min_scroll, set_topline)
  1964.     int        min_scroll;
  1965.     int        set_topline;
  1966. {
  1967.     int            used;
  1968.     int            scrolled = 0;
  1969.     int            extra = 0;
  1970.     int            sline;            /* screen line for cursor from bottom */
  1971.     int            i;
  1972.     linenr_t    lnum;
  1973.     linenr_t    line_count;
  1974.     linenr_t    old_topline = curwin->w_topline;
  1975.     linenr_t    old_botline = curwin->w_botline;
  1976.     int            old_empty_rows = curwin->w_empty_rows;
  1977.     linenr_t    cln;                /* Cursor Line Number */
  1978.  
  1979.     cln = curwin->w_cursor.lnum;
  1980.     if (set_topline)
  1981.     {
  1982.         used = 0;
  1983.         curwin->w_botline = cln + 1;
  1984.         for (curwin->w_topline = curwin->w_botline;
  1985.                 curwin->w_topline != 1;
  1986.                 --curwin->w_topline)
  1987.         {
  1988.             i = plines(curwin->w_topline - 1);
  1989.             if (used + i > curwin->w_height)
  1990.                 break;
  1991.             used += i;
  1992.         }
  1993.         curwin->w_empty_rows = curwin->w_height - used;
  1994.     }
  1995.  
  1996.     used = plines(cln);
  1997.     if (cln >= curwin->w_botline)
  1998.     {
  1999.         scrolled = used;
  2000.         if (cln == curwin->w_botline)
  2001.             scrolled -= curwin->w_empty_rows;
  2002.     }
  2003.  
  2004.     /*
  2005.      * Stop counting lines to scroll when
  2006.      * - hitting start of the file
  2007.      * - scrolled nothing or at least 'sj' lines
  2008.      * - at least 'so' lines below the cursor
  2009.      * - lines between botline and cursor have been counted
  2010.      */
  2011.     for (sline = 1; sline < cln; ++sline)
  2012.     {
  2013.         if ((((scrolled <= 0 || scrolled >= min_scroll) && extra >= p_so) ||
  2014.                 cln + sline > curbuf->b_ml.ml_line_count) &&
  2015.                 cln - sline < curwin->w_botline)
  2016.             break;
  2017.         i = plines(cln - sline);
  2018.         used += i;
  2019.         if (used > curwin->w_height)
  2020.             break;
  2021.         if (cln - sline >= curwin->w_botline)
  2022.         {
  2023.             scrolled += i;
  2024.             if (cln - sline == curwin->w_botline)
  2025.                 scrolled -= curwin->w_empty_rows;
  2026.         }
  2027.         if (cln + sline <= curbuf->b_ml.ml_line_count)
  2028.         {
  2029.             i = plines(cln + sline);
  2030.             used += i;
  2031.             if (used > curwin->w_height)
  2032.                 break;
  2033.             if (extra < p_so || scrolled < min_scroll)
  2034.             {
  2035.                 extra += i;
  2036.                 if (cln + sline >= curwin->w_botline)
  2037.                 {
  2038.                     scrolled += i;
  2039.                     if (cln + sline == curwin->w_botline)
  2040.                         scrolled -= curwin->w_empty_rows;
  2041.                 }
  2042.             }
  2043.         }
  2044.     }
  2045.     /* curwin->w_empty_rows is larger, no need to scroll */
  2046.     if (scrolled <= 0)
  2047.         line_count = 0;
  2048.     /* more than a screenfull, don't scroll but redraw */
  2049.     else if (used > curwin->w_height)
  2050.         line_count = used;
  2051.     /* scroll minimal number of lines */
  2052.     else
  2053.     {
  2054.         for (i = 0, lnum = curwin->w_topline;
  2055.                 i < scrolled && lnum < curwin->w_botline; ++lnum)
  2056.             i += plines(lnum);
  2057.         if (i >= scrolled)        /* it's possible to scroll */
  2058.             line_count = lnum - curwin->w_topline;
  2059.         else                /* below curwin->w_botline, don't scroll */
  2060.             line_count = 9999;
  2061.     }
  2062.  
  2063.     /*
  2064.      * Scroll up if the cursor is off the bottom of the screen a bit.
  2065.      * Otherwise put it at 1/2 of the screen.
  2066.      */
  2067.     if (line_count >= curwin->w_height && line_count > min_scroll)
  2068.         scroll_cursor_halfway(FALSE);
  2069.     else
  2070.         scrollup(line_count);
  2071.  
  2072.     /*
  2073.      * If topline didn't change we need to restore w_botline and w_empty_rows
  2074.      * (we changed them).
  2075.      * If topline did change, updateScreen() will set botline.
  2076.      */
  2077.     if (curwin->w_topline == old_topline && set_topline)
  2078.     {
  2079.         curwin->w_botline = old_botline;
  2080.         curwin->w_empty_rows = old_empty_rows;
  2081.     }
  2082. }
  2083.  
  2084. /*
  2085.  * Recompute topline to put the cursor halfway the window
  2086.  * If "atend" is TRUE, also put it halfway at the end of the file.
  2087.  */
  2088.     void
  2089. scroll_cursor_halfway(atend)
  2090.     int        atend;
  2091. {
  2092.     int            above = 0;
  2093.     linenr_t    topline;
  2094.     int            below = 0;
  2095.     linenr_t    botline;
  2096.     int            used;
  2097.     int            i;
  2098.     linenr_t    cln;                /* Cursor Line Number */
  2099.  
  2100.     topline = botline = cln = curwin->w_cursor.lnum;
  2101.     used = plines(cln);
  2102.     while (topline > 1)
  2103.     {
  2104.         if (below <= above)            /* add a line below the cursor */
  2105.         {
  2106.             if (botline + 1 <= curbuf->b_ml.ml_line_count)
  2107.             {
  2108.                 i = plines(botline + 1);
  2109.                 used += i;
  2110.                 if (used > curwin->w_height)
  2111.                     break;
  2112.                 below += i;
  2113.                 ++botline;
  2114.             }
  2115.             else
  2116.             {
  2117.                 ++below;            /* count a "~" line */
  2118.                 if (atend)
  2119.                     ++used;
  2120.             }
  2121.         }
  2122.  
  2123.         if (below > above)            /* add a line above the cursor */
  2124.         {
  2125.             i = plines(topline - 1);
  2126.             used += i;
  2127.             if (used > curwin->w_height)
  2128.                 break;
  2129.             above += i;
  2130.             --topline;
  2131.         }
  2132.     }
  2133.     curwin->w_topline = topline;
  2134. }
  2135.  
  2136. /*
  2137.  * Correct the cursor position so that it is in a part of the screen at least
  2138.  * 'so' lines from the top and bottom, if possible.
  2139.  * If not possible, put it at the same position as scroll_cursor_halfway().
  2140.  * When called topline and botline must be valid!
  2141.  */
  2142.     void
  2143. cursor_correct()
  2144. {
  2145.     int            above = 0;            /* screen lines above topline */
  2146.     linenr_t    topline;
  2147.     int            below = 0;            /* screen lines below botline */
  2148.     linenr_t    botline;
  2149.     int            above_wanted, below_wanted;
  2150.     linenr_t    cln;                /* Cursor Line Number */
  2151.     int            max_off;
  2152.  
  2153.     /*
  2154.      * How many lines we would like to have above/below the cursor depends on
  2155.      * whether the first/last line of the file is on screen.
  2156.      */
  2157.     above_wanted = p_so;
  2158.     below_wanted = p_so;
  2159.     if (curwin->w_topline == 1)
  2160.     {
  2161.         above_wanted = 0;
  2162.         max_off = curwin->w_height / 2;
  2163.         if (below_wanted > max_off)
  2164.             below_wanted = max_off;
  2165.     }
  2166.     if (curwin->w_botline == curbuf->b_ml.ml_line_count + 1)
  2167.     {
  2168.         below_wanted = 0;
  2169.         max_off = (curwin->w_height - 1) / 2;
  2170.         if (above_wanted > max_off)
  2171.             above_wanted = max_off;
  2172.     }
  2173.  
  2174.     /*
  2175.      * If there are sufficient file-lines above and below the cursor, we can
  2176.      * return now.
  2177.      */
  2178.     cln = curwin->w_cursor.lnum;
  2179.     if (cln >= curwin->w_topline + above_wanted && 
  2180.                                       cln < curwin->w_botline - below_wanted)
  2181.         return;
  2182.  
  2183.     /*
  2184.      * Narrow down the area where the cursor can be put by taking lines from
  2185.      * the top and the bottom until:
  2186.      * - the desired context lines are found
  2187.      * - the lines from the top is past the lines from the bottom
  2188.      */
  2189.     topline = curwin->w_topline;
  2190.     botline = curwin->w_botline - 1;
  2191.     while ((above < above_wanted || below < below_wanted) && topline < botline)
  2192.     {
  2193.         if (below < below_wanted && (below <= above || above >= above_wanted))
  2194.         {
  2195.             below += plines(botline);
  2196.             --botline;
  2197.         }
  2198.         if (above < above_wanted && (above < below || below >= below_wanted))
  2199.         {
  2200.             above += plines(topline);
  2201.             ++topline;
  2202.         }
  2203.     }
  2204.     if (topline == botline || botline == 0)
  2205.         curwin->w_cursor.lnum = topline;
  2206.     else if (topline > botline)
  2207.         curwin->w_cursor.lnum = botline;
  2208.     else
  2209.     {
  2210.         if (cln < topline && curwin->w_topline > 1)
  2211.             curwin->w_cursor.lnum = topline;
  2212.         if (cln > botline && curwin->w_botline <= curbuf->b_ml.ml_line_count)
  2213.             curwin->w_cursor.lnum = botline;
  2214.     }
  2215. }
  2216.  
  2217. /*
  2218.  * Compute curwin->w_row.
  2219.  * Can be called when topline and botline have not been updated.
  2220.  * return OK when cursor is in the window, FAIL when it isn't.
  2221.  */
  2222.     int
  2223. curs_rows()
  2224. {
  2225.     linenr_t    lnum;
  2226.     int            i;
  2227.  
  2228.     if (curwin->w_cursor.lnum < curwin->w_topline ||
  2229.                          curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count ||
  2230.                                    curwin->w_cursor.lnum >= curwin->w_botline)
  2231.         return FAIL;
  2232.  
  2233.     curwin->w_row = i = 0;
  2234.     for (lnum = curwin->w_topline; lnum != curwin->w_cursor.lnum; ++lnum)
  2235.         if (RedrawingDisabled)        /* curwin->w_lsize[] invalid */
  2236.             curwin->w_row += plines(lnum);
  2237.         else
  2238.             curwin->w_row += curwin->w_lsize[i++];
  2239.     return OK;
  2240. }
  2241.  
  2242. /*
  2243.  * compute curwin->w_col and curwin->w_virtcol
  2244.  */
  2245.     void
  2246. curs_columns(scroll)
  2247.     int scroll;            /* when TRUE, may scroll horizontally */
  2248. {
  2249.     int        diff;
  2250.     int        extra;
  2251.     int        new_leftcol;
  2252.     colnr_t    startcol;
  2253.     colnr_t endcol;
  2254.  
  2255.     getvcol(curwin, &curwin->w_cursor,
  2256.                                 &startcol, &(curwin->w_virtcol), &endcol);
  2257.  
  2258.         /* remove '$' from change command when cursor moves onto it */
  2259.     if (startcol > dollar_vcol)
  2260.         dollar_vcol = 0;
  2261.  
  2262.     curwin->w_col = curwin->w_virtcol;
  2263.     if (curwin->w_p_nu)
  2264.     {
  2265.         curwin->w_col += 8;
  2266.         endcol += 8;
  2267.     }
  2268.  
  2269.     curwin->w_row = curwin->w_cline_row;
  2270.     if (curwin->w_p_wrap)        /* long line wrapping, adjust curwin->w_row */
  2271.     {
  2272.         while (curwin->w_col >= Columns)
  2273.         {
  2274.             curwin->w_col -= Columns;
  2275.             curwin->w_row++;
  2276.         }
  2277.     }
  2278.     else if (scroll)    /* no line wrapping, compute curwin->w_leftcol if
  2279.                          * scrolling is on.  If scrolling is off,
  2280.                          * curwin->w_leftcol is assumed to be 0 */
  2281.     {
  2282.                         /* If Cursor is left of the screen, scroll rightwards */
  2283.                         /* If Cursor is right of the screen, scroll leftwards */
  2284.         if ((extra = (int)startcol - (int)curwin->w_leftcol) < 0 ||
  2285.              (extra = (int)endcol - (int)(curwin->w_leftcol + Columns) + 1) > 0)
  2286.         {
  2287.             if (extra < 0)
  2288.                 diff = -extra;
  2289.             else
  2290.                 diff = extra;
  2291.  
  2292.                 /* far off, put cursor in middle of window */
  2293.             if (p_ss == 0 || diff >= Columns / 2)
  2294.                 new_leftcol = curwin->w_col - Columns / 2;
  2295.             else
  2296.             {
  2297.                 if (diff < p_ss)
  2298.                     diff = p_ss;
  2299.                 if (extra < 0)
  2300.                     new_leftcol = curwin->w_leftcol - diff;
  2301.                 else
  2302.                     new_leftcol = curwin->w_leftcol + diff;
  2303.             }
  2304.             if (new_leftcol < 0)
  2305.                 curwin->w_leftcol = 0;
  2306.             else
  2307.                 curwin->w_leftcol = new_leftcol;
  2308.                     /* screen has to be redrawn with new curwin->w_leftcol */
  2309.             redraw_later(NOT_VALID);
  2310.         }
  2311.         curwin->w_col -= curwin->w_leftcol;
  2312.     }
  2313.         /* Cursor past end of screen */
  2314.         /* happens with line that does not fit on screen */
  2315.     if (curwin->w_row > curwin->w_height - 1)
  2316.         curwin->w_row = curwin->w_height - 1;
  2317. }
  2318.  
  2319.     void
  2320. scrolldown(line_count)
  2321.     long    line_count;
  2322. {
  2323.     register long    done = 0;    /* total # of physical lines done */
  2324.  
  2325.     /* Scroll up 'line_count' lines. */
  2326.     while (line_count--)
  2327.     {
  2328.         if (curwin->w_topline == 1)
  2329.             break;
  2330.         done += plines(--curwin->w_topline);
  2331.     }
  2332.     /*
  2333.      * Compute the row number of the last row of the cursor line
  2334.      * and move it onto the screen.
  2335.      */
  2336.     curwin->w_row += done;
  2337.     if (curwin->w_p_wrap)
  2338.         curwin->w_row += plines(curwin->w_cursor.lnum) -
  2339.                                               1 - curwin->w_virtcol / Columns;
  2340.     while (curwin->w_row >= curwin->w_height && curwin->w_cursor.lnum > 1)
  2341.         curwin->w_row -= plines(curwin->w_cursor.lnum--);
  2342.     comp_Botline(curwin);
  2343. }
  2344.  
  2345.     void
  2346. scrollup(line_count)
  2347.     long    line_count;
  2348. {
  2349.     curwin->w_topline += line_count;
  2350.     if (curwin->w_topline > curbuf->b_ml.ml_line_count)
  2351.         curwin->w_topline = curbuf->b_ml.ml_line_count;
  2352.     if (curwin->w_cursor.lnum < curwin->w_topline)
  2353.         curwin->w_cursor.lnum = curwin->w_topline;
  2354.     comp_Botline(curwin);
  2355. }
  2356.  
  2357. /*
  2358.  * Scroll the screen one line down, but don't do it if it would move the
  2359.  * cursor off the screen.
  2360.  */
  2361.     void
  2362. scrolldown_clamp()
  2363. {
  2364.     int        end_row;
  2365.  
  2366.     if (curwin->w_topline == 1)
  2367.         return;
  2368.  
  2369.     /*
  2370.      * Compute the row number of the last row of the cursor line
  2371.      * and make sure it doesn't go off the screen. Make sure the cursor
  2372.      * doesn't go past 'scrolloff' lines from the screen end.
  2373.      */
  2374.     end_row = curwin->w_row + plines(curwin->w_topline - 1);
  2375.     if (curwin->w_p_wrap)
  2376.         end_row += plines(curwin->w_cursor.lnum) - 1 -
  2377.                                                   curwin->w_virtcol / Columns;
  2378.     if (end_row < curwin->w_height - p_so)
  2379.         --curwin->w_topline;
  2380. }
  2381.  
  2382. /*
  2383.  * Scroll the screen one line up, but don't do it if it would move the cursor
  2384.  * off the screen.
  2385.  */
  2386.     void
  2387. scrollup_clamp()
  2388. {
  2389.     int        start_row;
  2390.  
  2391.     if (curwin->w_topline == curbuf->b_ml.ml_line_count)
  2392.         return;
  2393.  
  2394.     /*
  2395.      * Compute the row number of the first row of the cursor line
  2396.      * and make sure it doesn't go off the screen. Make sure the cursor
  2397.      * doesn't go before 'scrolloff' lines from the screen start.
  2398.      */
  2399.     start_row = curwin->w_row - plines(curwin->w_topline);
  2400.     if (curwin->w_p_wrap)
  2401.         start_row -= curwin->w_virtcol / Columns;
  2402.     if (start_row >= p_so)
  2403.         ++curwin->w_topline;
  2404. }
  2405.  
  2406. /*
  2407.  * insert 'line_count' lines at 'row' in window 'wp'
  2408.  * if 'invalid' is TRUE the wp->w_lsize_lnum[] is invalidated.
  2409.  * if 'mayclear' is TRUE the screen will be cleared if it is faster than
  2410.  * scrolling.
  2411.  * Returns FAIL if the lines are not inserted, OK for success.
  2412.  */
  2413.     int
  2414. win_ins_lines(wp, row, line_count, invalid, mayclear)
  2415.     WIN        *wp;
  2416.     int        row;
  2417.     int        line_count;
  2418.     int        invalid;
  2419.     int        mayclear;
  2420. {
  2421.     int        did_delete;
  2422.     int        nextrow;
  2423.     int        lastrow;
  2424.     int        retval;
  2425.  
  2426.     if (invalid)
  2427.         wp->w_lsize_valid = 0;
  2428.  
  2429.     if (RedrawingDisabled || line_count <= 0 || wp->w_height < 5)
  2430.         return FAIL;
  2431.     
  2432.     if (line_count > wp->w_height - row)
  2433.         line_count = wp->w_height - row;
  2434.  
  2435.     if (mayclear && Rows - line_count < 5)    /* only a few lines left: redraw is faster */
  2436.     {
  2437.         screenclear();        /* will set wp->w_lsize_valid to 0 */
  2438.         return FAIL;
  2439.     }
  2440.  
  2441.     /*
  2442.      * Delete all remaining lines
  2443.      */
  2444.     if (row + line_count >= wp->w_height)
  2445.     {
  2446.         screen_fill(wp->w_winpos + row, wp->w_winpos + wp->w_height,
  2447.                                                    0, (int)Columns, ' ', ' ');
  2448.         return OK;
  2449.     }
  2450.  
  2451.     /*
  2452.      * when scrolling, the message on the command line should be cleared,
  2453.      * otherwise it will stay there forever.
  2454.      */
  2455.     clear_cmdline = TRUE;
  2456.  
  2457.     /*
  2458.      * if the terminal can set a scroll region, use that
  2459.      */
  2460.     if (scroll_region)
  2461.     {
  2462.         scroll_region_set(wp, row);
  2463.         retval = screen_ins_lines(wp->w_winpos + row, 0, line_count,
  2464.                                                           wp->w_height - row);
  2465.         scroll_region_reset();
  2466.         return retval;
  2467.     }
  2468.  
  2469.     if (wp->w_next && p_tf)        /* don't delete/insert on fast terminal */
  2470.         return FAIL;
  2471.  
  2472.     /*
  2473.      * If there is a next window or a status line, we first try to delete the
  2474.      * lines at the bottom to avoid messing what is after the window.
  2475.      * If this fails and there are following windows, don't do anything to avoid
  2476.      * messing up those windows, better just redraw.
  2477.      */
  2478.     did_delete = FALSE;
  2479.     if (wp->w_next || wp->w_status_height)
  2480.     {
  2481.         if (screen_del_lines(0, wp->w_winpos + wp->w_height - line_count,
  2482.                                           line_count, (int)Rows, FALSE) == OK)
  2483.             did_delete = TRUE;
  2484.         else if (wp->w_next)
  2485.             return FAIL;
  2486.     }
  2487.     /*
  2488.      * if no lines deleted, blank the lines that will end up below the window
  2489.      */
  2490.     if (!did_delete)
  2491.     {
  2492.         wp->w_redr_status = TRUE;
  2493.         redraw_cmdline = TRUE;
  2494.         nextrow = wp->w_winpos + wp->w_height + wp->w_status_height;
  2495.         lastrow = nextrow + line_count;
  2496.         if (lastrow > Rows)
  2497.             lastrow = Rows;
  2498.         screen_fill(nextrow - line_count, lastrow - line_count,
  2499.                                                    0, (int)Columns, ' ', ' ');
  2500.     }
  2501.  
  2502.     if (screen_ins_lines(0, wp->w_winpos + row, line_count, (int)Rows) == FAIL)
  2503.     {
  2504.             /* deletion will have messed up other windows */
  2505.         if (did_delete)
  2506.         {
  2507.             wp->w_redr_status = TRUE;
  2508.             win_rest_invalid(wp->w_next);
  2509.         }
  2510.         return FAIL;
  2511.     }
  2512.  
  2513.     return OK;
  2514. }
  2515.  
  2516. /*
  2517.  * delete 'line_count' lines at 'row' in window 'wp'
  2518.  * If 'invalid' is TRUE curwin->w_lsize_lnum[] is invalidated.
  2519.  * If 'mayclear' is TRUE the screen will be cleared if it is faster than
  2520.  * scrolling
  2521.  * Return OK for success, FAIL if the lines are not deleted.
  2522.  */
  2523.     int
  2524. win_del_lines(wp, row, line_count, invalid, mayclear)
  2525.     WIN                *wp;
  2526.     int             row;
  2527.     int             line_count;
  2528.     int                invalid;
  2529.     int                mayclear;
  2530. {
  2531.     int            retval;
  2532.  
  2533.     if (invalid)
  2534.         wp->w_lsize_valid = 0;
  2535.  
  2536.     if (RedrawingDisabled || line_count <= 0)
  2537.         return FAIL;
  2538.     
  2539.     if (line_count > wp->w_height - row)
  2540.         line_count = wp->w_height - row;
  2541.  
  2542.     /* only a few lines left: redraw is faster */
  2543.     if (mayclear && Rows - line_count < 5)
  2544.     {
  2545.         screenclear();        /* will set wp->w_lsize_valid to 0 */
  2546.         return FAIL;
  2547.     }
  2548.  
  2549.     /*
  2550.      * Delete all remaining lines
  2551.      */
  2552.     if (row + line_count >= wp->w_height)
  2553.     {
  2554.         screen_fill(wp->w_winpos + row, wp->w_winpos + wp->w_height,
  2555.                                                    0, (int)Columns, ' ', ' ');
  2556.         return OK;
  2557.     }
  2558.  
  2559.     /*
  2560.      * when scrolling, the message on the command line should be cleared,
  2561.      * otherwise it will stay there forever.
  2562.      */
  2563.     clear_cmdline = TRUE;
  2564.  
  2565.     /*
  2566.      * if the terminal can set a scroll region, use that
  2567.      */
  2568.     if (scroll_region)
  2569.     {
  2570.         scroll_region_set(wp, row);
  2571.         retval = screen_del_lines(wp->w_winpos + row, 0, line_count,
  2572.                                                    wp->w_height - row, FALSE);
  2573.         scroll_region_reset();
  2574.         return retval;
  2575.     }
  2576.  
  2577.     if (wp->w_next && p_tf)        /* don't delete/insert on fast terminal */
  2578.         return FAIL;
  2579.  
  2580.     if (screen_del_lines(0, wp->w_winpos + row, line_count,
  2581.                                                     (int)Rows, FALSE) == FAIL)
  2582.         return FAIL;
  2583.  
  2584.     /*
  2585.      * If there are windows or status lines below, try to put them at the
  2586.      * correct place. If we can't do that, they have to be redrawn.
  2587.      */
  2588.     if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
  2589.     {
  2590.         if (screen_ins_lines(0, wp->w_winpos + wp->w_height - line_count,
  2591.                                                line_count, (int)Rows) == FAIL)
  2592.         {
  2593.             wp->w_redr_status = TRUE;
  2594.             win_rest_invalid(wp->w_next);
  2595.         }
  2596.     }
  2597.     /*
  2598.      * If this is the last window and there is no status line, redraw the
  2599.      * command line later.
  2600.      */
  2601.     else
  2602.         redraw_cmdline = TRUE;
  2603.     return OK;
  2604. }
  2605.  
  2606. /*
  2607.  * window 'wp' and everything after it is messed up, mark it for redraw
  2608.  */
  2609.     void
  2610. win_rest_invalid(wp)
  2611.     WIN            *wp;
  2612. {
  2613.     while (wp)
  2614.     {
  2615.         wp->w_lsize_valid = 0;
  2616.         wp->w_redr_type = NOT_VALID;
  2617.         wp->w_redr_status = TRUE;
  2618.         wp = wp->w_next;
  2619.     }
  2620.     redraw_cmdline = TRUE;
  2621. }
  2622.  
  2623. /*
  2624.  * The rest of the routines in this file perform screen manipulations. The
  2625.  * given operation is performed physically on the screen. The corresponding
  2626.  * change is also made to the internal screen image. In this way, the editor
  2627.  * anticipates the effect of editing changes on the appearance of the screen.
  2628.  * That way, when we call screenupdate a complete redraw isn't usually
  2629.  * necessary. Another advantage is that we can keep adding code to anticipate
  2630.  * screen changes, and in the meantime, everything still works.
  2631.  */
  2632.  
  2633. /*
  2634.  * types for inserting or deleting lines
  2635.  */
  2636. #define USE_T_CAL    1
  2637. #define USE_T_CDL    2
  2638. #define USE_T_AL    3
  2639. #define USE_T_CE    4
  2640. #define USE_T_DL    5
  2641. #define USE_T_SR    6
  2642. #define USE_NL        7
  2643. #define USE_T_CD    8
  2644.  
  2645. /*
  2646.  * insert lines on the screen and update NextScreen
  2647.  * 'end' is the line after the scrolled part. Normally it is Rows.
  2648.  * When scrolling region used 'off' is the offset from the top for the region.
  2649.  * 'row' and 'end' are relative to the start of the region.
  2650.  *
  2651.  * return FAIL for failure, OK for success.
  2652.  */
  2653.     static int
  2654. screen_ins_lines(off, row, line_count, end)
  2655.     int            off;
  2656.     int         row;
  2657.     int         line_count;
  2658.     int            end;
  2659. {
  2660.     int         i;
  2661.     int         j;
  2662.     char_u        *temp;
  2663.     int            cursor_row;
  2664.     int            type;
  2665.     int            result_empty;
  2666.  
  2667.     /*
  2668.      * FAIL if
  2669.      * - there is no valid screen 
  2670.      * - the screen has to be redrawn completely
  2671.      * - the line count is less than one
  2672.      * - the line count is more than 'ttyscroll'
  2673.      */
  2674.     if (!screen_valid(TRUE) || line_count <= 0 || line_count > p_ttyscroll)
  2675.         return FAIL;
  2676.  
  2677.     /*
  2678.      * There are seven ways to insert lines:
  2679.      * 1. Use T_CD (clear to end of display) if it exists and the result of
  2680.      *      the insert is just empty lines
  2681.      * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
  2682.      *    present or line_count > 1. It looks better if we do all the inserts
  2683.      *    at once.
  2684.      * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
  2685.      *    insert is just empty lines and T_CE is not present or line_count >
  2686.      *    1.
  2687.      * 4. Use T_AL (insert line) if it exists.
  2688.      * 5. Use T_CE (erase line) if it exists and the result of the insert is
  2689.      *    just empty lines.
  2690.      * 6. Use T_DL (delete line) if it exists and the result of the insert is
  2691.      *    just empty lines.
  2692.      * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
  2693.      *    the 'da' flag is not set or we have clear line capability.
  2694.      *
  2695.      * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
  2696.      * the scrollbar for the window. It does have insert line, use that if it
  2697.      * exists.
  2698.      */
  2699.     result_empty = (row + line_count >= end);
  2700.     if (*T_CD != NUL && result_empty)
  2701.         type = USE_T_CD;
  2702.     else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
  2703.         type = USE_T_CAL;
  2704.     else if (*T_CDL != NUL && result_empty && (line_count > 1 || *T_CE == NUL))
  2705.         type = USE_T_CDL;
  2706.     else if (*T_AL != NUL)
  2707.         type = USE_T_AL;
  2708.     else if (*T_CE != NUL && result_empty)
  2709.         type = USE_T_CE;
  2710.     else if (*T_DL != NUL && result_empty)
  2711.         type = USE_T_DL;
  2712.     else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || *T_CE))
  2713.         type = USE_T_SR;
  2714.     else
  2715.         return FAIL;
  2716.     
  2717.     /*
  2718.      * For clearing the lines screen_del_lines is used. This will also take
  2719.      * care of t_db if necessary.
  2720.      */
  2721.     if (type == USE_T_CD || type == USE_T_CDL ||
  2722.                                          type == USE_T_CE || type == USE_T_DL)
  2723.         return screen_del_lines(off, row, line_count, end, FALSE);
  2724.  
  2725.     /*
  2726.      * If text is retained below the screen, first clear or delete as many
  2727.      * lines at the bottom of the window as are about to be inserted so that
  2728.      * the deleted lines won't later surface during a screen_del_lines.
  2729.      */
  2730.     if (*T_DB)
  2731.         screen_del_lines(off, end - line_count, line_count, end, FALSE);
  2732.  
  2733.     if (*T_CSC != NUL)     /* cursor relative to region */
  2734.         cursor_row = row;
  2735.     else
  2736.         cursor_row = row + off;
  2737.  
  2738.     /*
  2739.      * Shift LinePointers line_count down to reflect the inserted lines.
  2740.      * Clear the inserted lines in NextScreen.
  2741.      */
  2742.     row += off;
  2743.     end += off;
  2744.     for (i = 0; i < line_count; ++i)
  2745.     {
  2746.         j = end - 1 - i;
  2747.         temp = LinePointers[j];
  2748.         while ((j -= line_count) >= row)
  2749.             LinePointers[j + line_count] = LinePointers[j];
  2750.         LinePointers[j + line_count] = temp;
  2751.         lineclear(temp);
  2752.     }
  2753.  
  2754.     windgoto(cursor_row, 0);
  2755.     if (type == USE_T_CAL)
  2756.     {
  2757.         OUTSTR(tgoto((char *)T_CAL, 0, line_count));
  2758.         screen_start();            /* don't know where cursor is now */
  2759.     }
  2760.     else
  2761.     {
  2762.         for (i = 0; i < line_count; i++) 
  2763.         {
  2764.             if (type == USE_T_AL)
  2765.             {
  2766.                 if (i && cursor_row != 0)
  2767.                     windgoto(cursor_row, 0);
  2768.                 outstr(T_AL);
  2769.             }
  2770.             else  /* type == USE_T_SR */
  2771.                 outstr(T_SR);
  2772.             screen_start();            /* don't know where cursor is now */
  2773.         }
  2774.     }
  2775.  
  2776.     /*
  2777.      * With scroll-reverse and 'da' flag set we need to clear the lines that
  2778.      * have been scrolled down into the region.
  2779.      */
  2780.     if (type == USE_T_SR && *T_DA)
  2781.     {
  2782.         for (i = 0; i < line_count; ++i) 
  2783.         {
  2784.             windgoto(off + i, 0);
  2785.             outstr(T_CE);
  2786.             screen_start();            /* don't know where cursor is now */
  2787.         }
  2788.     }
  2789.  
  2790.     return OK;
  2791. }
  2792.  
  2793. /*
  2794.  * delete lines on the screen and update NextScreen
  2795.  * 'end' is the line after the scrolled part. Normally it is Rows.
  2796.  * When scrolling region used 'off' is the offset from the top for the region.
  2797.  * 'row' and 'end' are relative to the start of the region.
  2798.  *
  2799.  * Return OK for success, FAIL if the lines are not deleted.
  2800.  */
  2801.     int
  2802. screen_del_lines(off, row, line_count, end, force)
  2803.     int                off;
  2804.     int             row;
  2805.     int             line_count;
  2806.     int                end;
  2807.     int                force;        /* even when line_count > p_ttyscroll */
  2808. {
  2809.     int         j;
  2810.     int         i;
  2811.     char_u        *temp;
  2812.     int            cursor_row;
  2813.     int            cursor_end;
  2814.     int            result_empty;    /* result is empty until end of region */
  2815.     int            can_delete;        /* deleting line codes can be used */
  2816.     int            type;
  2817.  
  2818.     /*
  2819.      * FAIL if
  2820.      * - there is no valid screen 
  2821.      * - the screen has to be redrawn completely
  2822.      * - the line count is less than one
  2823.      * - the line count is more than 'ttyscroll'
  2824.      */
  2825.     if (!screen_valid(TRUE) || line_count <= 0 ||
  2826.                                          (!force && line_count > p_ttyscroll))
  2827.         return FAIL;
  2828.  
  2829.     /*
  2830.      * Check if the rest of the current region will become empty.
  2831.      */
  2832.     result_empty = row + line_count >= end;
  2833.  
  2834.     /*
  2835.      * We can delete lines only when 'db' flag not set or when 'ce' option
  2836.      * available.
  2837.      */
  2838.     can_delete = (*T_DB == NUL || *T_CE);
  2839.  
  2840.     /*
  2841.      * There are four ways to delete lines:
  2842.      * 1. Use T_CD if it exists and the result is empty.
  2843.      * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
  2844.      * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
  2845.      *    none of the other ways work.
  2846.      * 4. Use T_CE (erase line) if the result is empty.
  2847.      * 5. Use T_DL (delete line) if it exists.
  2848.      */
  2849.     if (*T_CD != NUL && result_empty)
  2850.         type = USE_T_CD;
  2851.     else if (row == 0 && (line_count == 1 || *T_CDL == NUL))
  2852.         type = USE_NL;
  2853.     else if (*T_CDL != NUL && line_count > 1 && can_delete)
  2854.         type = USE_T_CDL;
  2855.     else if (*T_CE != NUL && result_empty)
  2856.         type = USE_T_CE;
  2857.     else if (*T_DL != NUL && can_delete)
  2858.         type = USE_T_DL;
  2859.     else if (*T_CDL != NUL && can_delete)
  2860.         type = USE_T_CDL;
  2861.     else
  2862.         return FAIL;
  2863.  
  2864.     if (*T_CSC != NUL)        /* cursor relative to region */
  2865.     {
  2866.         cursor_row = row;
  2867.         cursor_end = end;
  2868.     }
  2869.     else
  2870.     {
  2871.         cursor_row = row + off;
  2872.         cursor_end = end + off;
  2873.     }
  2874.  
  2875.     /*
  2876.      * Now shift LinePointers line_count up to reflect the deleted lines.
  2877.      * Clear the inserted lines in NextScreen.
  2878.      */
  2879.     row += off;
  2880.     end += off;
  2881.     for (i = 0; i < line_count; ++i)
  2882.     {
  2883.         j = row + i;
  2884.         temp = LinePointers[j];
  2885.         while ((j += line_count) <= end - 1)
  2886.             LinePointers[j - line_count] = LinePointers[j];
  2887.         LinePointers[j - line_count] = temp;
  2888.         lineclear(temp);
  2889.     }
  2890.  
  2891.     /* delete the lines */
  2892.     if (type == USE_T_CD)
  2893.     {
  2894.         windgoto(cursor_row, 0);
  2895.         outstr(T_CD);
  2896.         screen_start();                    /* don't know where cursor is now */
  2897.     }
  2898.     else if (type == USE_T_CDL)
  2899.     {
  2900.         windgoto(cursor_row, 0);
  2901.         OUTSTR(tgoto((char *)T_CDL, 0, line_count));
  2902.         screen_start();                    /* don't know where cursor is now */
  2903.     }
  2904.         /*
  2905.          * Deleting lines at top of the screen or scroll region: Just scroll
  2906.          * the whole screen (scroll region) up by outputting newlines on the
  2907.          * last line.
  2908.          */
  2909.     else if (type == USE_NL)
  2910.     {
  2911.         windgoto(cursor_end - 1, 0);
  2912.         for (i = line_count; --i >= 0; )
  2913.             outchar('\n');                /* cursor will remain on same line */
  2914.     }
  2915.     else
  2916.     {
  2917.         for (i = line_count; --i >= 0; )
  2918.         {
  2919.             if (type == USE_T_DL)
  2920.             {
  2921.                 windgoto(cursor_row, 0);
  2922.                 outstr(T_DL);           /* delete a line */
  2923.             }
  2924.             else /* type == USE_T_CE */
  2925.             {
  2926.                 windgoto(cursor_row + i, 0);
  2927.                 outstr(T_CE);           /* erase a line */
  2928.             }
  2929.             screen_start();                /* don't know where cursor is now */
  2930.         }
  2931.     }
  2932.  
  2933.     /*
  2934.      * If the 'db' flag is set, we need to clear the lines that have been
  2935.      * scrolled up at the bottom of the region.
  2936.      */
  2937.     if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
  2938.     {
  2939.         for (i = line_count; i > 0; --i)
  2940.         {
  2941.             windgoto(cursor_end - i, 0);
  2942.             outstr(T_CE);               /* erase a line */
  2943.             screen_start();                /* don't know where cursor is now */
  2944.         }
  2945.     }
  2946.     return OK;
  2947. }
  2948.  
  2949. /*
  2950.  * show the current mode and ruler
  2951.  *
  2952.  * If clear_cmdline is TRUE, clear the rest of the cmdline.
  2953.  * If clear_cmdline is FALSE there may be a message there that needs to be
  2954.  * cleared only if a mode is shown.
  2955.  */
  2956.     void
  2957. showmode()
  2958. {
  2959.     int        need_clear = FALSE;
  2960.     int        do_mode = (p_smd &&
  2961.                          ((State & INSERT) || restart_edit || VIsual_active));
  2962.  
  2963.     if (do_mode || Recording)
  2964.     {
  2965.         if (emsg_on_display)
  2966.         {
  2967.             mch_delay(1000L, TRUE);
  2968.             emsg_on_display = FALSE;
  2969.         }
  2970.         msg_didout = FALSE;                /* never scroll up */
  2971.         msg_col = 0;
  2972.         gotocmdline(FALSE);
  2973.         set_highlight('M');        /* Highlight mode */
  2974.         if (do_mode)
  2975.         {
  2976.             start_highlight();
  2977.             MSG_OUTSTR("--");
  2978. #ifdef INSERT_EXPAND
  2979.             if (edit_submode != NULL)        /* CTRL-X in Insert mode */
  2980.             {
  2981.                 msg_outstr(edit_submode);
  2982.                 if (edit_submode_extra != NULL)
  2983.                 {
  2984.                     msg_outchar(' ');        /* add a space in between */
  2985.                     if (edit_submode_highl)
  2986.                     {
  2987.                         stop_highlight();
  2988.                         set_highlight('r');        /* Highlight mode */
  2989.                         start_highlight();
  2990.                     }
  2991.                     msg_outstr(edit_submode_extra);
  2992.                     if (edit_submode_highl)
  2993.                     {
  2994.                         stop_highlight();
  2995.                         set_highlight('M');        /* Highlight mode */
  2996.                         start_highlight();
  2997.                     }
  2998.                 }
  2999.             }
  3000.             else
  3001. #endif
  3002.             {
  3003.                 if (State == INSERT)
  3004.                 {
  3005. #ifdef RIGHTLEFT
  3006.                     if (p_ri)
  3007.                         MSG_OUTSTR(" REVERSE");
  3008. #endif
  3009.                     MSG_OUTSTR(" INSERT");
  3010.                 }
  3011.                 else if (State == REPLACE)
  3012.                     MSG_OUTSTR(" REPLACE");
  3013.                 else if (restart_edit == 'I')
  3014.                     MSG_OUTSTR(" (insert)");
  3015.                 else if (restart_edit == 'R')
  3016.                     MSG_OUTSTR(" (replace)");
  3017. #ifdef RIGHTLEFT
  3018.                 if (p_hkmap)
  3019.                     MSG_OUTSTR(" Hebrew");
  3020. #endif
  3021.                 if ((State & INSERT) && p_paste)
  3022.                     MSG_OUTSTR(" (paste)");
  3023.                 if (VIsual_active)
  3024.                 {
  3025.                     MSG_OUTSTR(" VISUAL");
  3026.                     if (VIsual_mode == Ctrl('V'))
  3027.                         MSG_OUTSTR(" BLOCK");
  3028.                     else if (VIsual_mode == 'V')
  3029.                         MSG_OUTSTR(" LINE");
  3030.                 }
  3031.             }
  3032.             MSG_OUTSTR(" --");
  3033.             need_clear = TRUE;
  3034.         }
  3035.         if (Recording)
  3036.         {
  3037.             if (!need_clear)
  3038.                 start_highlight();
  3039.             MSG_OUTSTR("recording");
  3040.             need_clear = TRUE;
  3041.         }
  3042.         if (need_clear)
  3043.             stop_highlight();
  3044.         if (need_clear || clear_cmdline)
  3045.             msg_clr_eos();
  3046.         msg_didout = FALSE;                /* overwrite this message */
  3047.         msg_col = 0;
  3048.     }
  3049.     else if (clear_cmdline)                /* just clear anything */
  3050.     {
  3051.         msg_row = cmdline_row;
  3052.         msg_col = 0;
  3053.         msg_clr_eos();                    /* will reset clear_cmdline */
  3054.     }
  3055.     win_redr_ruler(lastwin, TRUE);
  3056.     redraw_cmdline = FALSE;
  3057. }
  3058.  
  3059. /*
  3060.  * delete mode message
  3061.  */
  3062.     void
  3063. delmode()
  3064. {
  3065.     if (Recording)
  3066.         MSG("recording");
  3067.     else
  3068.         MSG("");
  3069. }
  3070.  
  3071. /*
  3072.  * if ruler option is set: show current cursor position
  3073.  * if always is FALSE, only print if position has changed
  3074.  */
  3075.     void
  3076. showruler(always)
  3077.     int        always;
  3078. {
  3079.     win_redr_ruler(curwin, always);
  3080. }
  3081.  
  3082.     void
  3083. win_redr_ruler(wp, always)
  3084.     WIN        *wp;
  3085.     int        always;
  3086. {
  3087.     static linenr_t    old_lnum = 0;
  3088.     static colnr_t    old_col = 0;
  3089.     char_u            buffer[30];
  3090.     int                row;
  3091.     int                fillchar;
  3092.  
  3093.     if (p_ru && (redraw_cmdline || always ||
  3094.                 wp->w_cursor.lnum != old_lnum || wp->w_virtcol != old_col))
  3095.     {
  3096.         cursor_off();
  3097.         if (wp->w_status_height)
  3098.         {
  3099.             row = wp->w_winpos + wp->w_height;
  3100.             if (set_highlight('s') == OK)        /* can use highlighting */
  3101.             {
  3102.                 fillchar = ' ';
  3103.                 start_highlight();
  3104.             }
  3105.             else
  3106.                 fillchar = '=';
  3107.         }
  3108.         else
  3109.         {
  3110.             row = Rows - 1;
  3111.             fillchar = ' ';
  3112.         }
  3113.         /*
  3114.          * Some sprintfs return the length, some return a pointer.
  3115.          * To avoid portability problems we use strlen() here.
  3116.          */
  3117.         
  3118.         sprintf((char *)buffer, "%ld,",
  3119.                 (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) ?
  3120.                     0L :
  3121.                     (long)(wp->w_cursor.lnum));
  3122.         /*
  3123.          * Check if cursor.lnum is valid, since win_redr_ruler() may be called
  3124.          * after deleting lines, before cursor.lnum is corrected.
  3125.          */
  3126.         if (wp->w_cursor.lnum <= wp->w_buffer->b_ml.ml_line_count)
  3127.             col_print(buffer + STRLEN(buffer),
  3128.                 !(State & INSERT) &&
  3129.                 *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL ?
  3130.                     0 :
  3131.                     (int)wp->w_cursor.col + 1,
  3132.                     (int)wp->w_virtcol + 1);
  3133.  
  3134.         screen_msg(buffer, row, ru_col);
  3135.         screen_fill(row, row + 1, ru_col + (int)STRLEN(buffer),
  3136.                                             (int)Columns, fillchar, fillchar);
  3137.         old_lnum = wp->w_cursor.lnum;
  3138.         old_col = wp->w_virtcol;
  3139.         stop_highlight();
  3140.     }
  3141. }
  3142.  
  3143. /*
  3144.  * screen_valid -  allocate screen buffers if size changed 
  3145.  *   If "clear" is TRUE: clear screen if it has been resized.
  3146.  *        Returns TRUE if there is a valid screen to write to.
  3147.  *        Returns FALSE when starting up and screen not initialized yet.
  3148.  */
  3149.     int
  3150. screen_valid(clear)
  3151.     int        clear;
  3152. {
  3153.     screenalloc(clear);        /* allocate screen buffers if size changed */
  3154.     return (NextScreen != NULL);
  3155. }
  3156.  
  3157. #ifdef USE_MOUSE
  3158. /*
  3159.  * Move the cursor to the specified row and column on the screen.
  3160.  * Change current window if neccesary.  Returns an integer with the
  3161.  * CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
  3162.  *
  3163.  * If flags has MOUSE_FOCUS, then the current window will not be changed, and
  3164.  * if the mouse is outside the window then the text will scroll, or if the
  3165.  * mouse was previously on a status line, then the status line may be dragged.
  3166.  *
  3167.  * If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the
  3168.  * cursor is moved unless the cursor was on a status line.  Ignoring the
  3169.  * CURSOR_MOVED bit, this function returns one of IN_UNKNOWN, IN_BUFFER, or
  3170.  * IN_STATUS_LINE depending on where the cursor was clicked.
  3171.  *
  3172.  * If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
  3173.  * the last call.
  3174.  *
  3175.  * If flags has MOUSE_SETPOS, nothing is done, only the current position is
  3176.  * remembered.
  3177.  */
  3178.     int
  3179. jump_to_mouse(flags)
  3180.     int        flags;
  3181. {
  3182.     static int on_status_line = 0;        /* #lines below bottom of window */
  3183.     static int prev_row = -1;
  3184.     static int prev_col = -1;
  3185.  
  3186.     WIN        *wp, *old_curwin;
  3187.     FPOS    old_cursor;
  3188.     int        count;
  3189.     int        first;
  3190.     int        row = mouse_row;
  3191.     int        col = mouse_col;
  3192.  
  3193.     mouse_past_bottom = FALSE;
  3194.     mouse_past_eol = FALSE;
  3195.  
  3196.     if ((flags & MOUSE_DID_MOVE) && prev_row == mouse_row &&
  3197.                                                         prev_col == mouse_col)
  3198.         return IN_BUFFER;                /* mouse pointer didn't move */
  3199.  
  3200.     prev_row = mouse_row;
  3201.     prev_col = mouse_col;
  3202.  
  3203.     if ((flags & MOUSE_SETPOS))
  3204.         return IN_BUFFER;                /* mouse pointer didn't move */
  3205.  
  3206.     old_curwin = curwin;
  3207.     old_cursor = curwin->w_cursor;
  3208.  
  3209.     if (!(flags & MOUSE_FOCUS))
  3210.     {
  3211.         if (row < 0 || col < 0)        /* check if it makes sense */
  3212.             return IN_UNKNOWN;
  3213.  
  3214.         /* find the window where the row is in */
  3215.         for (wp = firstwin; wp->w_next; wp = wp->w_next)
  3216.             if (row < wp->w_next->w_winpos)
  3217.                 break;
  3218.         /*
  3219.          * winpos and height may change in win_enter()!
  3220.          */
  3221.         row -= wp->w_winpos;
  3222.         if (row >= wp->w_height)    /* In (or below) status line */
  3223.             on_status_line = row - wp->w_height + 1;
  3224.         else
  3225.             on_status_line = 0;
  3226.         win_enter(wp, TRUE);
  3227.         if (on_status_line)            /* In (or below) status line */
  3228.         {
  3229.             /* Don't use start_arrow() if we're in the same window */
  3230.             if (curwin == old_curwin)
  3231.                 return IN_STATUS_LINE;
  3232.             else
  3233.                 return IN_STATUS_LINE | CURSOR_MOVED;
  3234.         }
  3235.  
  3236.         curwin->w_cursor.lnum = curwin->w_topline;
  3237.     }
  3238.     else if (on_status_line)
  3239.     {
  3240.         /* Drag the status line */
  3241.         count = row - curwin->w_winpos - curwin->w_height + 1 - on_status_line;
  3242.         win_drag_status_line(count);
  3243.         return IN_STATUS_LINE;        /* Cursor didn't move */
  3244.     }
  3245.     else /* keep_window_focus must be TRUE */
  3246.     {
  3247.         row -= curwin->w_winpos;
  3248.  
  3249.         /*
  3250.          * When clicking beyond the end of the window, scroll the screen.
  3251.          * Scroll by however many rows outside the window we are.
  3252.          */
  3253.         if (row < 0)
  3254.         {
  3255.             count = 0;
  3256.             for (first = TRUE; curwin->w_topline > 1; --curwin->w_topline)
  3257.             {
  3258.                 count += plines(curwin->w_topline - 1);
  3259.                 if (!first && count > -row)
  3260.                     break;
  3261.                 first = FALSE;
  3262.             }
  3263.             redraw_later(VALID);
  3264.             row = 0;
  3265.         }
  3266.         else if (row >= curwin->w_height)
  3267.         {
  3268.             count = 0;
  3269.             for (first = TRUE; curwin->w_topline < curbuf->b_ml.ml_line_count;
  3270.                                                         ++curwin->w_topline)
  3271.             {
  3272.                 count += plines(curwin->w_topline);
  3273.                 if (!first && count > row - curwin->w_height + 1)
  3274.                     break;
  3275.                 first = FALSE;
  3276.             }
  3277.             redraw_later(VALID);
  3278.             row = curwin->w_height - 1;
  3279.         }
  3280.         curwin->w_cursor.lnum = curwin->w_topline;
  3281.     }
  3282.  
  3283. #ifdef RIGHTLEFT
  3284.     if (curwin->w_p_rl)
  3285.         col = Columns - 1 - col;
  3286. #endif
  3287.  
  3288.     if (curwin->w_p_nu)            /* skip number in front of the line */
  3289.         if ((col -= 8) < 0)
  3290.             col = 0;
  3291.  
  3292.     if (curwin->w_p_wrap)        /* lines wrap */
  3293.     {
  3294.         while (row)
  3295.         {
  3296.             count = plines(curwin->w_cursor.lnum);
  3297.             if (count > row)
  3298.             {
  3299.                 col += row * Columns;
  3300.                 break;
  3301.             }
  3302.             if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
  3303.             {
  3304.                 mouse_past_bottom = TRUE;
  3305.                 break;
  3306.             }
  3307.             row -= count;
  3308.             ++curwin->w_cursor.lnum;
  3309.         }
  3310.     }
  3311.     else                        /* lines don't wrap */
  3312.     {
  3313.         curwin->w_cursor.lnum += row;
  3314.         if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  3315.         {
  3316.             curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  3317.             mouse_past_bottom = TRUE;
  3318.         }
  3319.         col += curwin->w_leftcol;
  3320.     }
  3321.     curwin->w_curswant = col;
  3322.     curwin->w_set_curswant = FALSE;        /* May still have been TRUE */
  3323.     if (coladvance(col) == FAIL)
  3324.     {
  3325.         /* Mouse click beyond end of line */
  3326.         op_inclusive = TRUE;
  3327.         mouse_past_eol = TRUE;
  3328.     }
  3329.     else
  3330.         op_inclusive = FALSE;
  3331.  
  3332.     if ((flags & MOUSE_MAY_VIS) && !VIsual_active)
  3333.     {
  3334.         start_visual_highlight();
  3335.         VIsual = old_cursor;
  3336.         VIsual_active = TRUE;
  3337. #ifdef USE_MOUSE
  3338.         setmouse();
  3339. #endif
  3340.         if (p_smd)
  3341.             redraw_cmdline = TRUE;            /* show visual mode later */
  3342.     }
  3343.  
  3344.     if (curwin == old_curwin && curwin->w_cursor.lnum == old_cursor.lnum &&
  3345.                                        curwin->w_cursor.col == old_cursor.col)
  3346.         return IN_BUFFER;                /* Cursor has not moved */
  3347.     return IN_BUFFER | CURSOR_MOVED;    /* Cursor has moved */
  3348. }
  3349. #endif /* USE_MOUSE */
  3350.  
  3351. /*
  3352.  * Redraw the screen later, with UpdateScreen(type).
  3353.  * Set must_redraw only of not already set to a higher value.
  3354.  * e.g. if must_redraw is CLEAR, type == NOT_VALID will do nothing.
  3355.  */
  3356.     void
  3357. redraw_later(type)
  3358.     int        type;
  3359. {
  3360.     if (must_redraw < type)
  3361.         must_redraw = type;
  3362. }
  3363.